有几个关于如何处理computed property keys个Typescript 的问题需要解决,才能给你预期的行为.一个是microsoft/TypeScript#36920,其中计算的属性永远不会被视为excess properties,另一个是microsoft/TypeScript#38663,在microsoft/TypeScript#38663中,如果union类型的计算键与已知属性键部分冲突,它们最终将被完全忽略.这两个问题都被认为是功能请求(而不是错误,尽管后者会导致不健全).
额外的属性判断更像是Linter特性,而不是类型安全特性,并且不会应用到所有地方.在某种意义上,它们与文字类型系统的一个基本属性不一致:当您通过添加额外属性来为一个类型添加extend个属性时,新类型与旧类型仍然是structurally compatible.因此,在许多情况下,允许拥有过多的房产.它们只在涉及object literals的特定场景中被认为是错误,显然计算的属性不是这样的场景.也许它们应该是,就像微软/TypeScrip#36920建议的那样,但它们不是.所以在您的代码中,将random
添加为键的可能性不会引发任何警告.哦,好吧.这就解释了为什么{ valid?: string, random: number }
是允许的.
可能更有问题的是,联合类型的计算(computed)属性键一直被加宽到string
index signature(请参见microsoft/TypeScript#13948),然后在与其他属性组合时被静默地dropped.因此,const objB = { ...objA, [specKey]: 123123213 }
的类型只有{ valid?: string | undefined; }
,而不是预期的{ valid?: string, random: number } | { valid: number }
.我们知道{ valid?: string, random: number }
和TestObj
在 struct 上是兼容的,但{ valid: number }
是certainly not.没有人警告我们,我们可能会将number
分配给预期为string
的房产.这就是微软/TypeScrip#38663的建议.如果你想看到这一点发生,你可能想go 那个问题上,给它一个?.在实现这一点之前,您将需要绕过它.
我倾向于为索引签名问题使用的一种解决方法是将计算的属性键创建包装在一个帮助器函数中,该函数提供我所期望的类型.参见MICROSOFT/TypeScrip#13948上的第this comment页.例如,就像这样:
function kv<K extends PropertyKey, V>(k: K, v: V): { [P in K]: { [Q in P]: V } }[K] {
return { [k]: v } as any
}
然后,我写成{...kv(k, v)}
,而不是字面上的{[k]: v}
:
function testFunc(key: SpecKey) {
const objC: TestObj = { ...objA, ...kv(key, 123123123) }; // error!
// Type '{ valid: number; } | { random: number; valid?: string | undefined; }'
// is not assignable to type 'TestObj'
}
现在,您得到了预期的错误,具体地说,您正试图将类型为{ valid: number; } | { random: number; valid?: string }
的值赋给类型为{ valid?: string }
的变量,这是不允许的,因为number
不是string
.
Playground link to code个