Closed
Description
TypeScript Version: 3.7 - 4.1.0-dev.20200918
Search Terms:
abstract properties emit useDefineForClassFields
Code
Turn on useDefineForClassFields
abstract class A {
protected abstract x: number;
}
Expected behavior:
Abstract members are hint for typescript and they don't emit any code. So expected compiled code will be:
"use strict";
class A {
}
Actual behavior:
"use strict";
class A {
constructor() {
Object.defineProperty(this, "x", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
}
}
Consequence of such generation:
There is a larger problem caused by compiling abstract member.
There are 2 ways of override - using property or using getter/setter and they both should be (and are according to ts) compatible with abstract member. But only one of them is fine in runtime.
Code
Turn on useDefineForClassFields
abstract class A {
protected readonly abstract x: number;
public doSmth() {
console.log(this.x)
}
}
class B extends A {
protected x = 10
}
class C extends A {
protected get x() { return 7 }
}
new B().doSmth()
new C().doSmth()
Run compiled code
Expected behavior:
Output:
10
7
Compiled code:
"use strict";
class A {
doSmth() {
console.log(this.x);
}
}
class B extends A {
constructor() {
super(...arguments);
Object.defineProperty(this, "x", {
enumerable: true,
configurable: true,
writable: true,
value: 10
});
}
}
class C extends A {
get x() { return 7; }
}
new B().doSmth();
new C().doSmth();
Actual behavior:
Ouptut:
10
undefined
Compiled code:
"use strict";
class A {
constructor() {
Object.defineProperty(this, "x", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
}
doSmth() {
console.log(this.x);
}
}
class B extends A {
constructor() {
super(...arguments);
Object.defineProperty(this, "x", {
enumerable: true,
configurable: true,
writable: true,
value: 10
});
}
}
class C extends A {
get x() { return 7; }
}
new B().doSmth();
new C().doSmth();
Related Issues:
#31225