在下面的代码中,虽然一切看起来不错,但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警告,而不是编译错误。
可能是由于渐变类型系统引起的,但由于失败了,在这些情况下,应该有一个编译选项来解决此问题。
是否有任何解决方法或特殊的编译选项可以将其关闭?
答案 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)
(这也会引发完全相同的错误)
关于您当前的问题,最简单的解决方案是:
this.value
是数字if ((this.value as number) != 2)
if (+this.value != 2)
// @ts-ignore
注释,以便TypeScript编译器忽略该错误Ryan Cavanaugh提到了一些改进TypeScript的控制流分析的想法:
函数上的
pure
修饰符表示该函数不进行任何修改。这有点不切实际,因为我们实际上希望在所有函数中都使用它,并且它并不能真正解决问题,因为许多函数只能修改一件事,因此您真的想说“除“
volatile
属性修饰符,指出此“此属性将更改,恕不另行通知”。我们不是C ++,也许不清楚您将在哪里使用它,而不是在哪里。