TypeScript一直都有
in
operator narrowing
因此
if ("name" in val)
将有助于缩小
{name: string} | {age: number}
到
{name: string}
TypeScript 4.9介绍
unlisted property
narrowing with the
in
operator
因此
if ("age" in val)
会缩小
{name:string}
相当于
{name: string; age: unknown}
。是的,这些特征相互不一致。您可以在上阅读实施拉取请求
microsoft/TypeScript#50666
,以及的功能请求
microsoft/TypeScript#21732
讨论人们希望如何
在里面
操作员的工作,以及所涉及的权衡。
没有一种“正确”的心理模式在任何情况下都有效。TypeScript试图支持惯用的JavaScript,尽管这实际上并不是一个整体。TypeScript的类型系统是有意的
not sound
,以使开发人员能够富有成效。在其他条件相同的情况下,健全性比不健全性更受欢迎,但开发人员的生产力有时更重要。看见
TypeScript Design Non-Goal #3
.)
TypeScript
通常
将对象类型视为打开/可扩展的,而不是关闭/密封/精确的。所以价值
{a: "x", b: "y"}
可分配给
{a: string}
尽管它过剩
b
所有物但这些事情也是导致错误的原因,所以TypeScript有
excess property checks
和
在里面
运算符变窄。
为了
在里面
操作员,我想说心理模型是以下认知失调:如果你使用
在里面
检查某些中存在的属性
union
成员,TypeScript将把这些联合类型视为封闭/密封/精确的,并消除其他成员(即使这在技术上是不健全的)。另一方面,如果您正在使用
在里面
要检查任何联合成员中都不存在的属性,它会将该类型视为开放/可扩展类型,并只添加一个属性
unknown
类型转换为该对象类型。
因此,当你写作时
const test = (union: UnionBoth): void => {
if ('name' in union && 'age' in union) {
union.name
union.age
}
}
结果是:首先你检查
'name' in union
它变窄了
union
从…起
UnionBoth
到
{name:string}
,
消除
{age: number}
。然后检查
'age' in union
它变窄了
协会
从…起
{name:string}
到
{name: string, age: unknown}
。这完全符合上述心理模式,导致了这里坦率地说很奇怪的情况。如果您切换的顺序
在里面
测试,你会得到相反的奇怪结果。
在我看来,这表明:几乎没有人像你现在这样使用工会类型。如果他们正在检查属性
在里面
,是因为他们试图
区别对待
一个联合,即使这样做是不合理的。如果你真的想进行这种检查,你需要重构你的联合类型,以明确说明事情是如何工作的:
type UnionBoth = Name | Age | (Name & Age)
const test = (union: UnionBoth): void => {
if ('name' in union && 'age' in union) {
union;
// ^? Name & Age
union.name
// ^? string
union.age
// ^? number
}
}
现在的可能性
Name & Age
被明确提及,而TypeScript使用其原始
在里面
缩小到缩小到
名称&年龄
,永远不要使用新的“未列出的属性缩小”,因为总有一个联盟成员包含您要测试的密钥。
Playground link to code