【问题标题】:Why boolean becomes true?为什么布尔值变为真?
【发布时间】:2018-02-06 00:43:14
【问题描述】:

看看下面的code

export class Smth {
  private flag: boolean;

  public update() {
    this.flag = true;

    this.inner();

    if (this.flag === false) { // Operator '===' cannot be applied to types 'true' and 'false'.
      console.log(123);
    }
  }

  private inner() {
    this.flag = false;
  }
}

我不明白这行有什么问题

if (this.flag === false)

打字稿说

运算符 '===' 不能应用于类型 'true' 和 'false'。

但实际上有booleanfalse

我使用的是 typescript 2.6.2,但在线游乐场显示的结果与 2.7 相同。


这不是Operator '==' cannot be applied to types x and y in Typescript 2 的重复,因为该问题是关于比较常量的。但在我的代码中,它是一个可更改的类字段,并且有一个函数可以更改值。而且,它被称为。

this.flag = true;

this.inner(); // exectues this.flag = false;

if (this.flag === false) { // ... types 'true' and 'false'. - WHY?

【问题讨论】:

  • 你为什么不写if (!this.flag) { ... }
  • Operator '==' cannot be applied to types x and y in Typescript 2 的可能重复项(TL;DR:编译器可以看到您正在尝试将永远正确的事物与永远错误的事物进行比较)
  • @jonrsharpe,因为在实际代码中我有 3 个值的枚举。
  • 然后显示那个。请注意您发布的错误消息会导致许多现有资源,例如github.com/Microsoft/TypeScript/issues/11178
  • @JoeClay,不,这并不总是true。我打电话给this.inner(),它会将this.flag 的状态更改为false。标志不再是true

标签: typescript


【解决方案1】:

TypeScript 有点聪明,因为它对您的方法进行静态分析,并且它看到您从未分配除 false 以外的任何东西,至少在此闭包或上下文中 - 这带来了假设变量类型的类型定义是false 而不是boolean。它不寻找内部调用方法的变化。

把定义想象成是这样全局声明的:

export type boolean = true | false

虽然false 只是false,但那里没有true

有几种解决方案:

  1. 从一开始就在类声明中分配类型,如下所示:

    class MyClass {
      private flag: boolean = true
      ...
    }
    
  2. 只是不测试直接相等,单独使用布尔值:

    if (!this.flag) // instead of this.flag === false
    

【讨论】:

  • 查看private inner() 并致电this.inner() - 它会更改flag,因此您的假设似乎不正确。
  • 我注意到并指出“至少在这个闭包或上下文中”,静态分析不会在它检查的每个方法上流血
  • 我很难相信 typescript 编译器不理解调用其他方法的概念,可能会像本示例中那样更改类变量。这对我来说似乎是一个巨大的疏忽......如果标志的范围仅限于该功能,它会更有意义,但它不是......我认为你应该引用打字稿规范的相关部分来支持这一主张。
  • 这不是疏忽,而是设计使然。这也有某种意义,因为在静态分析中很难检查副作用github.com/Microsoft/TypeScript/issues/11178
【解决方案2】:

您遇到的问题是关于流量分析的缺点的更广泛讨论的一部分。您可以阅读一般问题here 以及与您的问题非常相似的问题here。但它的要点是:

主要问题是:当一个函数被调用时,我们应该假设它的副作用是什么? 一种选择是悲观并重置所有缩小范围,假设任何函数都可能改变它可能得到的任何对象。另一种选择是保持乐观并假设该函数不会修改任何状态。这两个似乎都不好。 这个问题涉及本地(可能会受到一些“封闭与否”分析)和对象字段。

解决此问题的简单方法是将常量转换为通用类型。您应该在必要时这样做,有人可能会认为该错误具有一定的价值,因为它会警告您可能无法访问的代码,并且可以在出现错误时轻松禁用:

export class Smth {
  private flag: boolean;

  public update() {
    this.flag = true as boolean;

    this.inner();

    if (this.flag === false) { 
      console.log(123);
    }
  }

  private inner() {
    this.flag = false;
  }
}

【讨论】:

    猜你喜欢
    • 2016-04-02
    • 2020-02-01
    • 2022-12-09
    • 1970-01-01
    • 2019-12-02
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多