例如,我将使用一个接收参数的函数并返回一个始终返回数字的函数。我有两个可能的结果:
如果我在第一个块中转换参数,则返回类型将丢失
// foo(bar: string | number) => () => string | number
function foo(bar: string | number) {
bar = +bar;
return function () {
return bar;
}
}
如果我在第二个块中转换参数,则返回类型将为 正确推断:
// foo2(bar2: string | number) => () => number
function foo2(bar2: string | number) {
return function () {
return +bar2;
}
}
为什么重新定义的参数的类型会丢失?
答案 0 :(得分:2)
TypeScript编译器使用control flow based type analysis来推断更窄类型的变量。如您所知,当您bar: string | number
并将其设置为+bar
时,bar
的值肯定会在之后立即成为number
。对于范围的其余部分,除非您再次重新定义bar
,否则TypeScript会知道bar
是number
。
除非没有。返回匿名函数function(){return bar;}
会引入closure,其中bar
的值将无限期地保持未检出状态,直到调用返回的函数为止。此时,TypeScript编译器放弃了。它不知道在调用该函数之前是否有人会将bar
的值更改为string
,因此它不会将缩小的类型保留在clousre中。
“等待”,你可能会说,“通过检查我可以看到,在我返回该函数后,bar
的值不会发生任何变化,所以永远都是number
。”你可能是对的。不幸的是,编译器并不像你那么聪明,在遇到闭包时放弃只是用于控制流量分析问题易于处理的许多启发式算法之一。
GitHub中存在一个很好的问题,即控制流动的难度是“正确的”:Microsoft/TypeScript #9998: Trade-offs in Control Flow Analysis。在许多情况下,编译器可能会被愚弄为无法缩小类型(不完整性)或过度缩小类型(不健全)。这就是它的方式,至少在我们达到technological singularity之前。
希望有所帮助;祝你好运!