这是一个基本用例:用 null 初始化变量,然后更改某些嵌套循环/函数中的值:
let a: number | null = null;
[1].forEach(() => {
a = 1;
});
if (a != null)
a.toFixed(); // Error: Property 'toFixed' does not exist on type 'never'.
然而,打字稿推断
a
的类型为 never
。我假设如果没有 if
它会假设它是 null | number
在这种情况下我可能会得到一个错误,指出该属性在 null 上不存在,但为什么它假设它永远不会仅基于初始分配值。
我做错了什么吗?
如果您绝对确定
a
在那里有值,那么您可以将!
放在变量之后
let a: number | null = null;
[1].forEach(() => {
a = 1;
});
if (a !== null)
a!.toFixed(); //
我不会使用
null
,但undefined
,所以不需要使用!
let a: number | undefined;
[1].forEach(() => {
a = 1;
});
if (a) { // <-- if undefined or 0
a.toFixed(); // No problem here
}
也建议使用
!==
而不是 !=
聚会迟到了,但这是我的 2 美分。
if (a) {
a.toFixed(); // No problem here
}
请注意,当 a
为
0
时,不会调用 if 块。
要解决此问题,请使用 if (a !== undefined)
0
a
初始化为0
,如下所示:
let a = 0; // typescript will infer the type number
...
if (a) {
// a is of type number and !== 0
}
回复评论
人们有时会这样做,因为某些工具(IDE,linter,..)否则会报告错误/警告。
例如当您使用 IntelliJ IDEA 和默认的 typescript 设置时,这是一个警告:
我建议停用这些检查,因为 javascript 中未初始化的变量始终具有值
undefined
:即在某些其他语言(即 C)中,该变量可能具有一些随机“垃圾”值。
引用自MDN:Global_Objects/undefined#description未赋值的变量的类型为未定义。not对于所有其他值(即
undefined
的值),打字稿编译器将显示错误:
TS2454: Variable 'xxx' is used before being assigned.
let a: number | null = null;
[1].forEach(() => {
a = 1;
});
if (a != null)
a.toFixed(); // Error: Property 'toFixed' does not exist on type 'never'.
只有当编译器选项
strictNullChecks
打开时才会发生这种情况。
这句话很好地描述了原因(引用参考虽然 strictNullChecks 意味着它只是检查可能未定义或 null 的变量的使用情况,但它确实将编译器转变为非常悲观的模式,当没有上下文方式推断类型时,它会选择最窄的类型,而不是最宽的类型,详细来说,这意味着:
由于打字稿编译器不够智能,无法知道是否调用了 forEach 循环(从而分配了值),因此它采用悲观方法并假设
a
null
因此,循环后 a
null
(不是我们想象的 number | null
)现在,最后的 if 块检查是否为 a !=== null
a
is
null
。因此, a
内部的类型if 语句是 never
所以一个“解决方案”是明确告诉打字稿您确定,a
a!.toFixed()
定义的
strictNullChecks
关闭时,代码可以工作:
TypeScript 示例:strictNullChecks=off我强烈建议不要这样做。
forEach()
时,即使
strictNullChecks
打开,代码也能正常工作:Playground
let a: number | null = null;
for (const i of [1]) {
a = 1;
};
if (a != null)
a.toFixed();
其他初始值
undefined
或
null
):Playground
let a = 0; // typescript will infer that a is of type number
[1].forEach(() => {
a = 1;
});
if (a >= 0)
a.toFixed();
let b = NaN; // typescript will infer that b is of type number
[1].forEach(() => {
a = 1;
});
if (!isNaN(b))
b.toFixed();