代码之家  ›  专栏  ›  技术社区  ›  user3690467

Typescript-错误推断“从不”

  •  0
  • user3690467  · 技术社区  · 5 年前

    这是一个基本的用例:使用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上,但为什么它会假设它永远不只是基于初始赋值。

    0 回复  |  直到 5 年前
        1
  •  4
  •   distante    5 年前

    如果你确信 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
    }
    

    也作为推荐使用 !== !=

        2
  •  1
  •   TmTron    3 年前

    派对迟到了,但这是我的2美分。

    if (a) {
      a.toFixed(); // No problem here
    }
    

    在以下情况下调用 a 0 .

    • 要解决此问题,请使用 if (a !== undefined)
    • 0 你最好还是离开这里 0
        let a = 0; // typescript will infer the type number
        ...
        if (a) {
          // a is of type number and !== 0
        }
    

    e、 g.当您将IntelliJ IDEA与默认的typescript设置一起使用时,这里有一个警告:
    enter image description here

    undefined :即,在某些其他语言(如C)中,变量可能有一些随机的“垃圾”值。

    引用自 MDN: Global_Objects/undefined#description

    未赋值的变量属于未定义类型。

    ),typescript编译器将显示错误:
    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意味着它只是在检查未定义或空的变量的使用情况,但它实际上会使编译器进入一种非常悲观的模式,当没有上下文方式来推断类型时,它会选择最窄的类型,而不是最宽的类型,

    具体而言,这意味着:

    • 由于typescript编译器不够聪明,无法知道是否调用了forEach循环(从而分配了一个值),因此它采用悲观的方法并假设 x 残余 null
    • 循环结束后 (不是 number | null 正如我们所料)
    • x !=== null 这种情况永远不会发生(因为typescript假设x 无效的 当执行if语句时。因此 if语句的内部是 never
    • 通过使用 x!.toFixed()

    杂项

    严格的空支票

    严格的空支票 关闭时,代码工作: TypeScript example: strictNullChecks=off

    当你使用for..of循环而不是 forEach() 即使在 严格的空支票 正在打开: Playground

    let a: number | null = null;
    for (const i of [1]) {
      a = 1;
    };
    if (a != null)
      a.toFixed();
    

    您还可以考虑其他初始化值(而不是 无效的 ): 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();