为什么"Object"可能未定义?



谁能向我解释为什么打字稿在这里抛出错误:

let a: number | undefined; 
let b = [2,3,4,5,6];
for (let c of b) {
a = 3;
if (!a) {
continue;
}
b.filter(x => +x !== +a);
}

链接

这是TypeScript的一般限制。 有关完整讨论,请参阅 microsoft/TypeScript#9998。

当你number | undefined获取联合类型的变量a并为其分配一个number(a = 3),或者对它进行真实性检查(if (!a) continue),类型检查器将其表观类型缩小到仅number,之后你可以将其视为number

a = 3;
if (!a) { continue; }
a.toFixed(2); // okay

不幸的是,缩小的影响并没有跨越功能边界。 在你传递给b.filter()的回调x => +x !== +a中,a的类型是顽固的number | undefined,而不仅仅是number,编译器认为+a可能undefineda是程序员的错误。

编译器不知道a是回调中的number的原因是因为它不知道何时运行回调,甚至不知道何时运行回调。由于闭包的工作方式,至少在语法上,当回调运行时,a可能会undefined

for (let c of b) {
a = 3;
if (!a) { continue; }
a.toFixed(2); // okay
someRandomFunction(x => +x !== +a);
}
a = undefined; // maybe

您知道a当您调用someRandomFunction时绝对是一个number,但据您所知,someRandomFunction等待一个小时然后调用回调,此时a已被后面的语句设置为undefined。 类型系统无法标记函数将立即调用其回调参数,因此filter()数组方法也可以someRandomFunction。 哦,好吧。


也许编译器有可能检测到在a的整个生命周期中它永远不会回到undefined,但这很难提高性能。 或者,也许可以在语言中引入immediate注释,以便filter()被视为"安全"......事实上,在 microsoft/TypeScript#11498 上有一个开放的功能请求,但目前尚未实现。

目前,只有解决方法。 到目前为止,最简单的方法是将缩小的表达式分配给一个新的const,然后在回调中使用const

const _a = a; // number
b.filter(x => +x !== +_a); // okay

由于此时a被缩小到number,当你写const _a = a时,编译器推断_anumber类型,而不是number | undefined。 没有必要缩小_a;它总是永远number在它存在的任何范围内。 因此,回调x => +x !== +a编译没有错误。

操场链接到代码

最新更新