为什么TypeScript逐步键入应停止编译此有效代码?

时间:2019-05-25 15:07:46

标签: typescript

在下面的代码中,虽然一切看起来不错,但TypeScript显示了一个看起来很奇怪的错误:

class Sample {

    private value = 1;

    private incrementValue(): void {
        this.value++; 
    }

    private beginTest(): void {

        if (this.value !== 1) {
            throw "bad state!"
        }

        this.incrementValue();

        if (this.value != 2) {
            throw "bad state!"; // ERROR!!: This condition will always return 'true' since the types '1' and '2' have no overlap.
        }
    }
}

为什么TypeScript会引发此类错误?我将value更改为this.incrementValue()。看来这种错误应该更多是 IntelliSense警告,而不是编译错误

可能是由于渐变类型系统引起的,但由于失败了,在这些情况下,应该有一个编译选项来解决此问题。

是否有任何解决方法或特殊的编译选项可以将其关闭?

1 个答案:

答案 0 :(得分:3)

尽管TypeScript的类型推断通常非常擅长正确地推断类型,但该语言的控制流分析却有限。微软TypeScript团队的首席开发人员认为:

  

主要问题是:调用函数时,我们应该假定它的副作用是什么?

     

一个选择是悲观的并且重置所有缩小的范围,假设任何函数都可能变异它可能会得到的任何对象。另一个选择是保持乐观,并假设函数不会修改任何状态。这两个似乎都不好。

     

— Ryan Cavanaugh,Trade-offs in Control Flow Analysis

您的示例的说明

在第一个if语句中,TypeScript将this.value评估为数字类型。

在第一个if语句之后,TypeScript确定this.value不再是number类型。相反,它属于literal type 1

这是因为任何不同于1(!== 1)的值都将终止该函数。因此,任何不会终止而是继续执行下一个if语句的值都必须是确切的文字值1

当您调用this.incrementValue();时,TypeScript不知道该函数会改变this.value的状态。到第二条if语句时,TypeScript仍然相信this.value的文字类型为1

因此,它以与您用数字文字this.value替换1相同的方式评估第二个if语句

if (1 != 2)

(这也会引发完全相同的错误)

您的问题的解决方案

关于您当前的问题,最简单的解决方案是:

  • 告诉TypeScript this.value是数字if ((this.value as number) != 2)
  • 将该值转换为数字if (+this.value != 2)
  • 在上一行添加// @ts-ignore注释,以便TypeScript编译器忽略该错误

改善TypeScript控制流分析的解决方案

Ryan Cavanaugh提到了一些改进TypeScript的控制流分析的想法:

  
      函数上的
  • pure修饰符表示该函数不进行任何修改。这有点不切实际,因为我们实际上希望在所有函数中都使用它,并且它并不能真正解决问题,因为许多函数只能修改一件事,因此您真的想说“除“

  •   
  • volatile属性修饰符,指出此“此属性将更改,恕不另行通知”。我们不是C ++,也许不清楚您将在哪里使用它,而不是在哪里。

  •