我有一个对象并想使用字符串变量访问它,但是我收到错误:
no index signature with a parameter of type 'string' was found on type '{ A: number; B: number; C: number; }'
const obj = {
"A":1,
"B":2,
"C":3
}
const f=(str:string)=>{
const result = obj[str];
}
但是,这个编译和结果
不应该具有number|undefined
类型吗?解决这个问题的唯一方法是将 str
转换为 keyof typeof obj
,如所述 here ?我还想过这样做 if (Object.keys(obj).includes(str))
... 但这并没有将 str
的类型缩小为仅有效键。
最佳答案
TypeScript 中的对象类型是“开放”或“可扩展”,而不是“封闭”或“精确”。对象类型的值需要具有已知的属性,但通常不禁止具有额外的未知属性。开放且可扩展的对象类型非常有用:它们允许接口(interface)和类扩展形成类型层次结构;所以 interface Bar extends Foo { extraProp: string }
意味着每个 Bar
也是 Foo
,尽管 Foo
的定义不知道关于 extraProp
的任何信息。但它确实产生了让开发人员感到惊讶的影响。目前还没有真正支持确切的类型(尽管 excess property checking 确实有时看起来不是这样);请参阅 microsoft/TypeScript#12936 了解相关功能请求。
让我们检查一下编译器推断的 obj
的类型:
/* const obj: {
A: number;
B: number;
C: number;
} */
这意味着编译器知道 obj
在键 A
、 B
和 C
处具有数字属性。但由于对象类型是开放的,编译器不知道它缺少所有其他属性。尽管分配给 obj
的对象文字确实缺少任何其他属性,但类型系统不会跟踪此类信息。就编译器而言,obj
可能有也可能没有各种其他属性。它只会让你在没有警告的情况下访问 A
、 B
和 C
(无论如何都是 --strict
或 --noImplicitAny
),但是如果你用一些未知的 string
键对其进行索引,编译器会说“那可能是 any
” ”。
TypeScript 可以指定未知属性类型的最接近方法是使用 index signature ,例如 {[k: string]: number | undefined}
。
您不能说“A
、 B
和 C
的类型为 number
并且所有其他属性均为 undefined
”,因为这需要不同类型的索引签名来表示“所有其他属性”(有关相关功能,请参阅 microsoft/TypeScript#17867要求)。相反,您可以说“A
、 B
和 C
是 number
,所有属性都是 number | undefined
。或者,如果您并不真正关心跟踪 A
、 B
,和 C
,你可以这样做上面提到的“所有属性都是 string | undefined
通过以下类型注释:
const obj: {[k: string]: number | undefined} = {
"A": 1,
"B": 2,
"C": 3
};
const f = (str: string) => {
const result = obj[str]; // number | undefined
}
现在您的函数将返回 number | undefined
,如您所愿。
关于typescript - 自动推断变量属于键集中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65874824/