打字稿编译误差比较可变枚举成员变量

问题描述:

当我收到错误:打字稿编译误差比较可变枚举成员变量

TS2365: Operator '===' cannot be applied to types 'ExampleState.Unsaved' and 'ExampleState.Saving'. 

当针对一个可变成员变量进行比较的枚举:

enum ExampleState { 
    Unset = -1, 
    Unsaved = 0, 
    Saving = 1, 
    Saved = 2 
} 

class Example { 

    private state : ExampleState = ExampleState.Unset; 

    public Save() { 
     if (this.state === ExampleState.Unsaved) { 
      this.BeginSaving(); 
      while (this.state === ExampleState.Saving) { // !error! 
       this.CommitSave(); 
      } 
     } 
    } 

    private BeginSaving() { 
     this.state = ExampleState.Saving; 
    } 

    private CommitSave() { 
     this.state = ExampleState.Saved; 
    } 
} 

真正的例子是一个异步方法,它多次尝试保存 - 这已被简化为只是说明错误。

Typescript似乎并不明白这个变量是可变的,并且过于积极地假设它没有被改变。为什么会发生这种情况,解决方法是什么?

+0

您可以使用'while(this.state as any === ExampleState.Saving)'作为解决方法。但我建议你[将案例提交给TypeScript团队](https://github.com/Microsoft/TypeScript/issues)。 – Paleo

+1

同样的建议,虽然我宁愿这样做: 'while(this.state as ExampleState === ExampleState.Saving)' –

+2

有一个公开的问题:https://github.com/Microsoft/TypeScript/问题/ 9998 – Magu

这是一个know issus from the Control flow analysis

As another workaround您可以为state属性创建一个包装方法。 (谢谢@Paleo)

访问Playground

enum ExampleState { 
    Unset = -1, 
    Unsaved = 0, 
    Saving = 1, 
    Saved = 2 
} 

class Example { 

    private state : ExampleState = ExampleState.Unset; 

    private State() { 
     return this.state; 
    } 

    public Save() { 
     if (this.State() === ExampleState.Unsaved) { 
      this.BeginSaving(); 
      while (this.State() === ExampleState.Saving) { 
       this.CommitSave(); 
      } 
     } 
    } 

    private BeginSaving() { 
     this.state = ExampleState.Saving; 
    } 

    private CommitSave() { 
     this.state = ExampleState.Saved; 
    } 
} 

这是因为ExampleState.Unsaved不仅是价值,而且还是一种类型(let x: ExampleState.Unsaved在语义上是有效的)。打字稿有所谓的型后卫,和你的

if (this.state === ExampleState.Unsaved) 

说法是这样的控卫 - 打字稿假设this.state内部的语句总是ExampleState.Unsaved类型。

我怀疑枚举类型,就像联盟类型实际处理,所以你的代码就相当于(这也不起作用):

type ExampleState = -1 | 0 | 1 | 2; 
class Example { 

    private state : ExampleState = -1; 

    public Save() { 
     if (this.state === 0) { 
      this.BeginSaving(); 
      while (this.state === 1) { // !error! 
       this.CommitSave(); 
      } 
     } 
    } 

    private BeginSaving() { 
     this.state = 1; 
    } 

    private CommitSave() { 
     this.state = 2; 
    } 
} 

正如@Paleo说,我认为这是值得提交给TypeScript团队(如果尚未由其他人发送)。现在,我建议在您的while声明中输入铸件。与使用while的解决方案相比,它可以产生与您最初想要的完全相同的JavaScript输出。

while (this.state as ExampleState === ExampleState.Saving) { // no error 
    this.CommitSave(); 
} 
+1

理想情况下,有人会在打开一个新的之前搜索相关的问题。正如@Magu所说,这是由[Microsoft/TypeScript#9998](https://github.com/Microsoft/TypeScript/issues/9998)所涵盖。 – jcalz