TypeScript Refinement type inference quirk with implicitly typed let x

6pp0gazn  于 3个月前  发布在  TypeScript
关注(0)|答案(5)|浏览(41)

🔎 搜索词

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; )有一个简单的解决方法。
然而,这种不对称性,即最后一个条件在缩小时失败,而前一个条件在该时机成功,让我感到困扰。我之所以报告这个问题,是因为它可能是更一般实现缺陷的症状。

nbysray5

nbysray51#

尽管承认可能存在一些实际限制,但这种行为并不一致。鉴于第一个条件确实会缩小范围,并且它在使用显式类型注解时可以正常工作,我将冒着风险说这可能是一个错误。

jq6vz3qz

jq6vz3qz2#

问题在于getDiscriminantPropertyAccess的实现方式以及它可以访问的信息:
https://github.dev/microsoft/TypeScript/blob/b4787652d281188da1d61fe9cc3a17589f20c9fc/src/compiler/checker.ts#L27675-L27676
在这一点上,computedType仅仅是{ type: 'B' }(所以不是联合类型),但declaredType也不是联合类型(它是自动类型)。因此,这个函数不幸地忽略了最后的检查。

eoxn13cs

eoxn13cs3#

哦,哇,我知道只有联合检查(union checks)才适用于具有联合declaredType值的变量(我想安德斯在之前提到过这一点,并且在GH问题中偶尔会出现),但我从未想过这种逻辑可能是出错的原因。

oogrdqng

oogrdqng4#

尽管如此,我仍然认为这是一个bug。这是一个以非常奇怪的方式泄漏的实现细节-尤其是因为这个联合体在最后一次检查之前被很好地区分开来,而此时它已经被减少为一个单一成员。

f45qwnt8

f45qwnt85#

哦,是的,我同意这是一个bug,我并不是想表达我认为不是这样。这只是奇怪的是它是一个看似100%无害的“这是声明为联合”检查的涌现行为。

相关问题