TypeScript Version: 3.7.0-beta
Search Terms: public class fields
Code:
class Base {}
class Sub extends Base {
// @ts-ignore
constructor() {
console.log('hi');
super();
}
field = 0;
}
new Sub();
Expected behavior:
The input code is valid (future) JS that does not throw. So the emitted code should equally not throw.
Actual behavior:
The emitted code throws ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.
The reason is that if a sub-class has field initializers, TypeScript currently requires the first line of the constructor to be super(). This is a restriction of TypeScript, not of JavaScript. If you violate this rule, the emitted code crashes.
Emitted code:
class Base {}
class Sub extends Base {
// @ts-ignore
constructor() {
this.field = 0;
console.log('hi');
super();
}
}
new Sub();
Playground Link: Playground repro
Related Issues: Issue 33751 was marked as a duplicate and auto-closed. I think this missed my comment so opening this as an independent issue.
@ts-ignore
馃槨
You can't @ts-ignore the error that effectively says "We do not downlevel this code correctly" and then be surprised that the downlevel is wrong. #8277 tracks the work to handle pre-super statements correctly; this is still a duplicate.
I think this is actually orthogonal - the linked issue discusses making the analysis smarter. This issue is about ensuring that we transform to "do the right thing" despite any shortcomings of our analysis.
I'm on mobile, but willing to bet we don't error here when compiling .js files without checkJs - so we should probably at least fix the transform which is easier than #8277.
Thanks Daniel - you are correct. Using "allowJS": true and putting the code in a .js file results in bad emitted code.
So this issue is not about the checker. I apologize to @RyanCavanaugh for causing confusion by using @ts-ignore in the example code.
That's true. We balked at this originally because super can appear in arbitrary positions and the true downlevel for it gets pretty hairy.
(Weird that there's no ESNext label anymore?)
Might be a good idea to keep the emit the same when the first statement is a super() call, and come up with a more general emit for super() in arbitrary positions.
Closing this as a duplicate of #35426 since it has less noise in the conversation, as well as a nice expected/actual pair.
Most helpful comment
馃槨