问题是提议添加类字段声明 https://github.com/tc39/proposal-class-fields#class-field-declarations-for-javascriptJavaScript 的语义与您可能期望的语义以及 TypeScript 设计者将它们添加到 TypeScript 时的期望不同。事实证明,在 JavaScript 中,类字段声明将通过以下方式初始化Object.defineProperty() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty而不是通过赋值,所有此类没有初始化器的声明字段都将被初始化为undefined
。所以最终你可以期望像你这样的代码生成设置的 JavaScripta
to undefined
在子类中,即使您的目的只是缩小基类的类型。布莱奇。
所以,在 TypeScript 3.7 中,a --useDefineForClassFields添加了标志,以及declare属性修饰符 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#the-usedefineforclassfields-flag-and-the-declare-property-modifier。如果你使用--useDefineForClassFields
,编译器将输出符合预期的代码Object.defineProperty()
类字段的语义:
如果你使用该标志按原样运行您的代码 https://www.typescriptlang.org/play?useDefineForClassFields=true#code/MYGwhgzhAECC0G8BQSC+LSRgIWgUwA8AXPAOwBMZ5lppyB7AZXoFs8iALAS1IHMAKAJSJo6dEkxRoAeVJ5ESWsHqkIRAE4BXYEXrr+AB3X0SOvOWhgAXHGEJRaDOCkAVAO718xMpRlyFtEYmeGYW1tC4APSR0AAKxgZ46kQAntAA5GDp0ByQ0KSePFxEXGAgXABeSZYU0FwwBUR0eABmRSQgaVhcvHIWPNCc8sqqGtq66gB0KEoqalo6ekIBtNAQmon6cm4RQoIA3Iqr0dAAki1n+KQk6tAARJz1k2DQALz5eDvYQvt3OUnyIakQYceRJYy3cj1MAGRJgdQQAA00AARpomkNoMpyPJ6tB1OZNBQwNdprRxLQGIwiJoWi1ljRVo8IM9JlTWOxuHwhEcxChttB3PQhGymDS6UIgA,你会在运行时看到这个问题:
new Two().doStuff()
// [ERR]: "Executed JavaScript Failed:"
// [ERR]: this.a is undefined
解决方案是使用declare
属性修饰符缩小子类属性而不发出任何相应的Object.defineProperty()
code:
class Two extends One {
declare protected a: B // okay
constructor() {
super(new B());
}
doStuff() {
this.a.doSomething()
}
}
new Two().doStuff(); // okay now
Playground 代码链接 https://www.typescriptlang.org/play?useDefineForClassFields=true#code/MYGwhgzhAECC0G8BQSC+LSRgIWgUwA8AXPAOwBMZ5lppyB7AZXoFs8iALAS1IHMAKAJSJo6dEkxRoAeVJ5ESWsHqkIRAE4BXYEXrr+AB3X0SOvOWhgAXHGEJRaDOCkAVAO718xMpRlyFtOR4mOryRibBJBbW0LgA9HHQ9ADWYACeKEoqalo6ekIBtNAQmgZ4+nJusUKCANyKDg0MjESaAGZtBTRFnFwQAHRg-c2s7Nx8Qg1iKJXQ7vRCw0ytHQUJ0KSe5cbqQA