如何修复“属性没有初始值设定项并且未在构造函数中明确分配”错误?

问题描述

我在使用这些课程时遇到了问题。我想使用 doSomething() 类专有的方法 B 而不每次都进行类型转换,但是当我将属性 a 指定为 B 类型时,它告诉我它没有在构造函数中赋值,这有点错误,因为父构造函数进行了赋值。

class A {

}

class B extends A {
  doSomething() { }
}

class One {
  constructor(protected a: A){  }
}

class Two extends One {
  protected a: B // Property 'a' has no initializer and is not definitely assigned in the constructor.

  constructor(){
    super(new B());
    // If I enter "this.a = new B();" here then the error disappears,but the code is redundant.
  }

  doStuff() {
    this.a.doSomething()
  }
}

我做错了什么?

Playground

解决方法

问题在于,将 class field declarations 添加到 JavaScript 的提议与您可能期望的语义以及 TypeScript 设计人员将它们添加到 TypeScript 时所期望的语义不同。事实证明,在 JavaScript 中,类字段声明将通过 Object.defineProperty() 而不是通过赋值进行初始化,并且所有此类没有初始化器的声明字段都将使用 undefined 进行初始化。因此,最终您可以期望像您这样的代码生成在子类中将 a 设置为 undefined 的 JavaScript,即使您的目的只是从基类中缩小类型。布莱克。

因此,在 TypeScript 3.7 中,a --useDefineForClassFields flag was added,along with the declare property modifier。如果您使用 --useDefineForClassFields,编译器将输出符合类字段的预期 Object.defineProperty() 语义的代码:

如果您run your code as-is with that flag,您会在运行时看到问题:

new Two().doStuff()
// [ERR]: "Executed JavaScript Failed:" 
// [ERR]: this.a is undefined 

解决方案是使用 declare 属性修饰符来缩小子类属性的范围,而不发出任何相应的 Object.defineProperty() 代码:

class Two extends One {
  declare protected a: B // okay

  constructor() {
    super(new B());
  }

  doStuff() {
    this.a.doSomething()
  }
}

new Two().doStuff(); // okay now

Playground link to code

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...