谁能向我解释为什么打字稿在这里抛出错误:
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
可能undefined
a
是程序员的错误。
编译器不知道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
时,编译器推断_a
是number
类型,而不是number | undefined
。 没有必要缩小_a
;它总是永远number
在它存在的任何范围内。 因此,回调x => +x !== +a
编译没有错误。
操场链接到代码