这是一个基本用例:使用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上,但是为什么要假定它永远不会基于null呢?只是初始赋值。
我做错什么了吗?
答案 0 :(得分:3)
如果您完全确定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) {
a.toFixed(); // No problem here
}
还建议使用!==
而不是!=
答案 1 :(得分:1)
聚会迟到了,但这是我的 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、linters 等)会以其他方式报告错误/警告。
例如当您使用 IntelliJ IDEA 和默认的打字稿设置时,这是一个警告:
我建议停用这些检查,因为 javascript 中未初始化的变量始终具有值 undefined
:即在某些其他语言(即 C)中,该变量可能具有一些随机的“垃圾”值。
引用自 MDN: Global_Objects/undefined#description
<块引用>未赋值的变量是 undefined 类型。
对于所有其他值(即非 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 的变量的使用情况,但它确实将编译器变成了一种非常悲观的模式,当没有上下文推断类型时,它将选择最窄的类型, 而不是最宽的类型,
这意味着:
x
仍然是 null
x
的类型是 null
(不是我们预期的 number | null
)x !=== null
这永远不会是这种情况(因为 typescript 在执行 if 语句时假定 x is null
。因此if 语句中 x
的类型是 never
x
的值是通过使用 x!.toFixed()
定义的当 strictNullChecks
关闭时,代码有效:TypeScript example: strictNullChecks=off
我强烈建议不要这样做。
当您使用 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();