我正在尝试一些TS索引签名示例,感觉键的限制行为非常不一致。
const s = Symbol();
type DictNumber = {
[key: number]: string;
}
const dictNumber: DictNumber ={
1: 'andy', // no error, which is what I defined.
'foo': 'bar', // Error, because the key is string not a number.
[s]: 'baz', // no error, but why ??? [s] is a symbol not a number right?
}
type DictString = {
[key: string]: string;
}
const dictString: DictString={
1: 'andy', // no error? why? is it converted from number to string for me?
'foo': 'bar', // no error, which is what I defined.
[s]: 'baz', // no error, but why ??? [s] is a symbol not a string right?
}
type DictSymbol= {
[key: symbol]: string;
}
const dictSymbol: DictSymbol={
1: 'andy', // Error, because the key is number not a symbol.
'foo': 'bar', // no error, why?
[s]: 'baz', // no error, which is what I defined.
我有noImplicitAny
和alwaysStrict
以及.这里是操场
我可能错过了一些非常基本的东西,有人能给我解释一下为什么会发生这种情况吗?
3条答案
按热度按时间cgh8pdjw1#
它比表面上看起来更有趣。考虑一下这个:
但尝试修复
foo
密钥:所以,现在我们知道,有一个错误,但由于错误突出显示算法,它没有突出显示,因为有另一个错误,这是抛出更快。或者尝试只是替换它们:
我理解TS团队这样做的原因,为了性能。如果我们已经有了错误,就不需要再验证更多的键了。
const dictSymbol: DictSymbol
也是一样。它工作正常,试着更换它们。只有
DictString
没有达到我们的预期,完全没有错误。根据我的经验,这是因为
Record<K,V>
没有interface
表示安全,因为类型别名是默认索引的,请看我的答案。为了安全起见,请使用
interface
:如果您将
DictString
转换为interface
,则会出现更多错误:我不知道为什么这里没有错误。我希望
gtlvzcf82#
这里有许多问题在起作用。
具有如下索引签名
意味着每个 numeric 属性必须具有
string
类型。但是 non-numeric 属性的类型没有任何限制。这意味着这是可以的:编辑:正如来自乌克兰的@captain-yossarian在他的回答中指出的,存在一个多余的属性检查错误。至少在数字索引签名方面是这样。
您预期的错误主要取决于 * 多余的属性检查 *。是的,当您将 * 对象文本 * 赋给具有显式类型的变量时,TypeScript确实执行多余的属性检查。
但是目前存在#44794中描述的一个bug。当索引签名存在时,编译器不会在过多的属性检查中检测
symbol
-属性。这是一种意外行为,可能会在将来某个时候修复。
最后:
当索引时数字被强制为字符串,这就是为什么当
string
索引签名存在时允许数字作为属性的原因。pw9qyyiw3#
TL;DR
JS对象不是字典,您要查找的是
Map
长答案
符号保证是唯一的,因此不是普通的键,它们作为一种存储对象的半私有(可以用
Object.getOwnPropertySymbols()
访问)属性的方式存在,而不会与其他键冲突。这是一种弱封装形式。TypeScript知道符号不会干扰其他对象键,因此允许将它们用作键。
由于JavaScript对象不是字典,就像Python和c#中的字典一样,你可以在同一个对象中混合特殊键。TypeScript是JavaScript的超集,必须支持这种行为,你可以向任何对象添加私有属性,而不管键的类型。
此外,由于对象已经具有本机Symbol键,因此可以添加更多的Symbol键。
至于这种行为的合理性,JS的答案通常是“因为它很奇怪”。
使用“record”代替“dict/dictionary”更好,它也是一个built in utility type in TypeScript。