聚会迟到了,但这是我的 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
}
回复评论
为什么要使用 undefined 来初始化变量?
人们有时会这样做,因为某些工具(IDE、linter、..)否则会报告错误/警告。
例如当您使用具有默认 typescript 设置的 IntelliJ IDEA 时,会出现以下警告:
我建议停用这些检查,因为 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 开启时发生。
这句话很好地描述了原因(Quote Reference)
虽然 strictNullChecks 暗示它只是检查可能未定义或为 null 的变量的使用,但它确实将编译器变成了一种非常悲观的模式,当没有上下文推断类型的方法时,它会选择最窄的类型,而不是最宽的类型,
这意味着,详细地说:
- 由于 typescript 编译器不够聪明,无法知道是否调用了 forEach 循环(因此分配了一个值),它采用悲观的方法并假设
x 仍然是 null
- 因此,循环后
x 的类型是null(而不是我们预期的number | null)
- 现在,最后一个 if 块检查
x !=== null 是否永远不会是这种情况(因为 typescript 假设在执行 if 语句时 x 是 null。因此 @ 的类型if 语句中的 987654348@ 是 never
- 所以一个“解决方案”是明确告诉 typescript 你确定,
x 的值是通过使用 x!.toFixed() 定义的
杂项
strictNullChecks
当strictNullChecks 关闭时,代码有效:TypeScript example: strictNullChecks=off
我强烈建议不要这样做。
for..of 循环
当您使用 for..of 循环而不是 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();