【发布时间】:2020-10-03 15:23:37
【问题描述】:
我将今天遇到的一个问题简化为这个最小的示例。 (playground link)
function test() {
interface Foo<T> {
type: 'Bar'
}
function nextFoo<T>(it: Foo<T>): Foo<T> {
return it
}
let foo: Foo<string> | undefined = { type: 'Bar' }
while (foo !== undefined) {
// Type inference error here but TS has the correct inference when hovering over nextFoo
const next = nextFoo(foo)
foo = next // commenting this out masks the issue
}
}
这似乎是 TypeScript 应该能够处理的事情。当我在 vscode 中将鼠标悬停在 nextFoo 上时,它看起来确实可以正确推断出那里的类型。将foo 设置为next 而可能是undefined 会导致这种情况。
有人能解释一下这里发生了什么吗?
【问题讨论】:
-
编译器看到
next的类型取决于foo的类型,这显然取决于next的类型(因为将next分配给foo将重置任何控制-流量变窄)。const next: Foo<string> =的显式类型注释将修复它。我认为这与microsoft/TypeScript#1146 中的问题基本相同。 -
@jcalz 我不明白为什么
foo的类型推断取决于next。它已经明确设置正确了吗?我在任何地方(给人类)分配给 foo 的内容都没有关系,类型不会与我声明的类型不同。在能够通过从foo类型中删除| undefined来解决此问题的上下文中,我也无法理解该解释。这也解决了这个问题,而无需输入next,因此必须在某处发生其他事情。 -
控制流分析发生在测试或分配联合类型的值时。所以
foo = next,其中foo的声明类型是联合类型,对foo的表观类型有影响。这意味着编译器的类型推断依赖关系图将显示foo的类型取决于next的类型。显然,人类只能“看到”类型应该是什么,但编译器使用了一种明显检测循环性的特定算法。我应该把它写下来作为答案还是我还缺少什么? -
@jcalz 是的,我认为这是一个很好的答案。我从中得到的是,在处理涉及联合类型的类型推断时,它是编译器实现的副作用。我不知道我是否应该将其视为错误。天真地,它似乎可以在具有指定类型的条件下被短路,或者只是通过在硬编码类型时不尝试通过图形推断类型而一起规避,就像
foo分配的情况一样。跨度>