【问题标题】:Initializing class properties in TypeScript using ES6 class getters / setters使用 ES6 类 getter/setter 在 TypeScript 中初始化类属性
【发布时间】:2021-03-23 09:23:52
【问题描述】:

我正在尝试在类构造函数中初始化一个变量。但是,我希望检查该值并对其施加一些约束,因此我使用了 ES6 类 getter/setter。

我遇到的问题是我从构造函数中调用了 setter,但 TypeScript 抱怨说:

(属性) Meter._status: 字符串 属性 '_status' 没有初始化器,也没有在构造函数中明确分配。

我知道我可以直接在构造函数中初始化 _status。但是,如前所述,我需要检查值并强制执行其他约束。

这在 TypeScript 中是不可能的吗?如果是的话,我该怎么做,给出下面的例子。

class Meter {

    private _status: string;

    constructor(status: string) {
      this.status = status;
    } 

    set status(status:string) {
      if(status === 'on' || status === 'off') {
        this._status = status
      } else {
          console.log('Invalid status provided');
      }
    }

    get status() {
      return this._status
    }

}

export default Meter;

我知道我也可以先用空字符串初始化属性,然后将值设置如下。但是,它感觉有点hacky,并且在添加更多属性时会添加很多额外的代码。

class Meter {

    private _status: string;

    constructor(status: string) {
      // initialize _status with an empty string
      this._status = '';

      // set the actual value of status
      this.status = status;
    } 

    set status(status:string) {
      if(status === 'on' || status === 'off') {
        this._status = status
      } else {
          console.log('Invalid status provided');
      }
      
    }
    get status() {
      return this._status
    }

}

export default Meter;

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您可以使用Definite Assignment Assertions。它告诉 TypeScript 确实为所有意图和目的分配了一个变量,即使 TypeScript 的分析无法检测到这一点。

    class Meter {
        private _status!: string;
        //            ^^^ definite assignment assertion
    
        constructor(status: string) {
          this.status = status;
        } 
    
        set status(status:string) {
          if(status === 'on' || status === 'off') {
            this._status = status
          } else {
              console.log('Invalid status provided');
          }
        }
    
        get status() {
          return this._status
        }
    }
    
    export default Meter;
    

    Playground

    【讨论】:

      【解决方案2】:

      其实很简单。你只需要像这样添加一个属性初始化器:

      class Meter {
      
          private _status: string = '';
      
          constructor(status: string) {
            // set the actual value of status
            this.status = status;
          } 
      
          set status(status:string) {
            if(status === 'on' || status === 'off') {
              this._status = status
            } else {
                console.log('Invalid status provided');
            }
            
          }
          get status() {
            return this._status
          }
      
      }
      
      export default Meter;
      

      编辑:正如 Shivam Singla 提到的,您也可以像这样使用定义赋值断言:

      class Meter {
      
          private _status!: string;
      
          constructor(status: string) {
            // set the actual value of status
            this.status = status;
          } 
      
          set status(status:string) {
            if(status === 'on' || status === 'off') {
              this._status = status
            } else {
                console.log('Invalid status provided');
            }
      
          }
          get status() {
            return this._status
          }
      
      }
      
      export default Meter;
      

      它告诉 TypeScript 编译器假装值将在那里初始化。如果你想试试,代码在这里:

      【讨论】:

      • 非常感谢。我不确定在构造函数中初始化属性是否是最佳实践,或者我可以像您的示例中那样做。
      • 我想我这样做的唯一问题是属性类型是否比字符串复杂一些。例如一个类型化的对象。这可能需要相当多的额外代码才能以这种方式初始化许多属性。