考虑这个简单的片段。我也把它贴在这里:
type A =
| {
b: number;
}
| {
c: number;
};
function f1(a: A) {
if ('b' in a) {
return a['b']; // No problem!
}
return 42;
}
function f2(a: A) {
const key = 'b';
if (key in a) {
return a[key]; // Property 'b' does not exist on type 'A'
}
return 42;
}
为什么a
的类型没有缩小到{b: number}
中的f2
?(与f1
相同)
3条答案
按热度按时间nhn9ugyo1#
这本质上与microsoft/TypeScript#10530的问题相同;控制流分析中的类型缩小只会发生在直接为文字的属性(如
"b"
),而不会发生在类型为文字类型的任意表达式中。第10530期讨论通过财产访问缩小...像a.b
或a["b"]
,这 * 确实 * 导致a
变窄,而a[key]
,这 * 不 *。正如您所注意到的,
in
操作符类型保护也会发生这种情况(如microsoft/TypeScript#15256中实现的),其中"b" in a
缩小了a
的类型,但key in a
没有。在#10530中没有明确提到这一点(它早于in
类型保护),但我不认为有另一个存在的问题。根据microsoft/TypeScript#10565,最初尝试解决#10530中的问题,为文字类型的任意表达式添加类型保护功能会显着恶化编译器性能。也许对所有
x in y
检查执行额外的分析比对所有y[x]
属性访问执行额外的分析要便宜,但至少到目前为止没有人关心。你可以随时在GitHub上打开你自己的问题(许多问题最终都是重复的,我不能100%确定这不会被认为是#10530的重复,或者没有其他问题重复),但实际上,它可能不会很快改变。
如果您想要一个变通方法来解决无法用字符串文字替换
key
的情况,您可以编写自己的用户定义的类型保护函数hasProp(obj, prop)
。实现只返回prop in obj
,但它的类型签名显式地表明true
结果应该导致obj
缩小到那些键类型为prop
的联合成员:然后在函数中,将
key in a
替换为hasProp(a, key)
:Playground链接到代码
nlejzf6q2#
你需要像这样的自定义类型保护函数:
TypeScript不会缩小存储在变量中的键的类型,显然是出于性能原因。
有关另一种方法以及为什么TypeScript不这样做的详细原因,请参阅以下答案:https://stackoverflow.com/a/64618261/13651701
qrjkbowd3#
在旧版本的3.6.3中,上述两个现有的答案都不适用于我。由于我的目标环境,我被困在旧版本中。请看下面我的工作版本: