🔎 搜索词
refinement narrow let any
🕗 版本与回归信息
- 在版本3.9.7和4.0.5之间有所变化;从4.0.5到5.3的每个版本中都存在这种行为;我浏览了整个FAQ文档,但没有找到任何相关的内容
⏯ Playground链接
https://www.typescriptlang.org/play?ts=5.3.0-dev.20231013#code/C4TwDgpgBAsiAq5oF4oG8qkgLigcgEE8oBfKAH3UyVzwCFiSBuAKBYDMBXAOwGNgAlgHtuUdgAoAhgCcA5rjiJIASnQsoGqABsIwKAA9Wmg1FQzZRzQPZRx+gHRYUyVITyq06zWQhaAztDWtg5Opi74DB5eGj7+0J7Gxjp6APq43BAAbhDSpgaWMSwkLEA
💻 代码
type MyType = { type: 'A' } | { type: 'B' };
function f(arg: MyType) {
let x;
x = arg;
if (x.type === 'A') {
} else if (x.type === 'B') {
} else {
let _: never = x;
}
}
🙁 实际行为
error TS2322: Type '{ type: "B"; }' is not assignable to type 'never'.
9 let _: never = x;
~
这种情况是错误的,原因有两点:
- 在完美的类型推断世界里,
x
应该在这个点上缩小为never
- 即使承认可能存在一些实际限制,行为也不一致。
第一个条件成功消除了"A"变体:
但是第二个条件未能消除"B"变体:
🙂 预期行为
理想情况下,这不应该是一个错误。
然而,鉴于基于控制流的类型推断具有其局限性,也许某种虚假错误是不可避免的。在这种情况下,它可能更像是 Type 'MyType' is not assignable to type 'never'
而不是 Type '{ type: "B" }' is not assignable to type 'never'
。
关于此问题的其他信息
这个问题的实际影响很小。添加一个显式类型注解( let x: MyType;
)有一个简单的解决方法。
然而,这种不对称性,即最后一个条件在缩小时失败,而前一个条件在该时机成功,让我感到困扰。我之所以报告这个问题,是因为它可能是更一般实现缺陷的症状。
5条答案
按热度按时间nbysray51#
尽管承认可能存在一些实际限制,但这种行为并不一致。鉴于第一个条件确实会缩小范围,并且它在使用显式类型注解时可以正常工作,我将冒着风险说这可能是一个错误。
jq6vz3qz2#
问题在于
getDiscriminantPropertyAccess
的实现方式以及它可以访问的信息:https://github.dev/microsoft/TypeScript/blob/b4787652d281188da1d61fe9cc3a17589f20c9fc/src/compiler/checker.ts#L27675-L27676
在这一点上,
computedType
仅仅是{ type: 'B' }
(所以不是联合类型),但declaredType
也不是联合类型(它是自动类型)。因此,这个函数不幸地忽略了最后的检查。eoxn13cs3#
哦,哇,我知道只有联合检查(union checks)才适用于具有联合
declaredType
值的变量(我想安德斯在之前提到过这一点,并且在GH问题中偶尔会出现),但我从未想过这种逻辑可能是出错的原因。oogrdqng4#
尽管如此,我仍然认为这是一个bug。这是一个以非常奇怪的方式泄漏的实现细节-尤其是因为这个联合体在最后一次检查之前被很好地区分开来,而此时它已经被减少为一个单一成员。
f45qwnt85#
哦,是的,我同意这是一个bug,我并不是想表达我认为不是这样。这只是奇怪的是它是一个看似100%无害的“这是声明为联合”检查的涌现行为。