typescript - TypeScript:如何准确地为复杂对象键入函数(带有索引签名)
问题描述
概述
我有一个函数需要返回对象中的特定位置。这里没有什么不寻常的。我面临的问题是该对象是已知索引和索引签名的混合,并且该函数似乎变得混乱。我希望我只是在做一些愚蠢的事情并输入错误的功能,并且你们中的一个好人可以让我知道我做错了什么......但这感觉就像一个 TS linter 错误。任何帮助将不胜感激(包括尽可能简化......但我真的只关心解决我的特定打字问题)。
功能
function getCounts<Entity extends EntityType>(entity: Entity, id: string): Counts[Entity][string] {
return counts[entity][id] ?? []; // throws the error
}
错误
Type 'CountsWithEntity<Entity1> | CountsWithEntity<Entity2>' is not assignable to type 'Counts[Entity][string]'.
Type 'CountsWithEntity<Entity1>' is not assignable to type 'Counts[Entity][string]'.
但它有效!
并且推断的类型,在使用函数时,是正确的
娱乐链接
完整代码(娱乐链接中的相同代码)
type Entity1 = { hello: string };
type Entity2 = { world: string };
enum EntityType {
entity1 = 'hello',
entity2 = 'world',
}
type Entities = Entity1 | Entity2;
type EntityMap = {
[EntityType.entity1]: Entity1;
[EntityType.entity2]: Entity2;
};
type CountsWithEntity<Entity extends Entities> = Array<{
count: number;
entity: Entity;
}>;
type Counts = {
[entityKey in EntityType]: {
[id: string]: CountsWithEntity<EntityMap[entityKey]>;
};
};
const counts: Counts = {
[EntityType.entity1]: {
id1: [
{
count: 2,
entity: { hello: 'hi' },
},
{
count: 1,
entity: { hello: 'you' },
},
],
id2: [
{
count: 3,
entity: { hello: 'bye' },
},
{
count: 4,
entity: { hello: 'cya' },
},
],
},
[EntityType.entity2]: {
id3: [
{
count: 6,
entity: { world: 'earth' },
},
{
count: 5,
entity: { world: 'place' },
},
],
id4: [
{
count: 8,
entity: { world: 'dirt' },
},
{
count: 7,
entity: { world: 'huh?' },
},
],
},
};
function getCounts<Entity extends EntityType>(entity: Entity, id: string): Counts[Entity][string] {
return counts[entity][id] ?? []; // throws the error
}
console.log(counts[EntityType.entity1].id1); // expected `[{ count: 2, entity: { hello: 'hi' } }, { count: 1, entity: { hello: 'you' } }]` - success, no TS errors
console.log(getCounts(EntityType.entity1, 'id1')); // expected `[{ count: 2, entity: { hello: 'hi' } }, { count: 1, entity: { hello: 'you' } }]` - success, no TS errors
console.log(getCounts(EntityType.entity2, 'id3')[0].entity.world); // expected `"earth"` - success, no TS errors
解决方案
该错误告诉您您的返回类型应该是CountsWithEntity<Entity1> | CountsWithEntity<Entity2>
.
那是因为类型counts[entity][id]
是CountsWithEntity<EntityMap[entityKey]>
- 尝试以下
function getCounts<Entity extends EntityType>(entity: Entity, id: string): CountsWithEntity<Entity1> | CountsWithEntity<Entity2> {
return counts[entity][id] ?? []; // throws the error
}
此外
您还可以使用返回类型CountsWithEntity<EntityMap[EntityType]>
更加动态。
function getCounts<Entity extends EntityType>(entity: Entity, id: string): CountsWithEntity<EntityMap[EntityType]> {
return counts[entity][id] ?? []; // throws the error
}
推荐阅读
- javascript - 如何导出和解构对象?
- tsql - 根据哪个现有字段具有字符串匹配,为新字段分配值
- python-3.x - Python将文件保存到错误的路径
- javascript - 首次上传后 Dropzone ProcessQueue 事件未命中服务器
- tensorflow - 类不可知掩码 R-CNN
- node.js - 如何在节点 js 中使用 woocommerce api 更新订单
- python - Numpy 1D 数组在广播时被视为列向量
- python - 使用 selenium 单击展开和折叠按钮
- struct - Bigquery:STRUCT (*) 语法
- javascript - 如何创建一个函数来显示和隐藏具有“标题”类的行之间的所有表行?