-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
In classes that extend ES5 constructor functions, the value returned by a call to super() within the constructor does not match the value of this.
function A() {}
class B extends A {
constructor() {
const _super = super();
if (_super !== this) {
throw new Error(`Expected ${_super} to equal this`);
}
}
}
new B(); // throws Error: Expected undefined to equal thisIt seems that the return value of the base constructor function is used as the return value of super(), unless the constructor function returns an object.
function A() { return 'test'; }
// class B as above
new B(): // throws Error: Expected test to equal thisfunction A() { return { test: true }; }
// class B as above
new B(): // does not throwclass A { constructor() { return 'test'; }}
// class B as above
new B(): // also does not throw when A is a class instead of ES5 constructor functionChrome, Firefox, and Safari do not throw in any of these cases.
I found this because code similar to this is generated by Babel when transforming async arrow function properties that reference this. The async function transform uses a generator function, and since generator arrow functions aren't yet available, the generator function closes over the return value of super() for use in place of this in the former arrow function. React.Component is distributed as an ES5 constructor function, so my React components that use async arrow function properties all produce this problem code -- React.Component has no return statement, so in my case super() returns undefined.
Here's some example code that causes Babel to produce the problem code: https://babeljs.io/repl/#?babili=false&browsers=&build=&builtIns=false&code_lz=GYVwdgxgLglg9mABAYTgWwA4IKZigCgEoBvAXwChyIAbAQwGd7EB1GAEwHNspFsAPKLjZNUmHHkTFyiRAEg-iALyIA5AAts1anBUBuaTMRs4AZXTc1MMByWIGAT0iIiSgHySDhwxAT041bAA6bQ58KEt6QL5CT0QKCnIwbAB3FnYuAkJA4zM0CytQwl0gA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=true&fileSize=false&lineWrap=false&presets=es2017%2Cstage-2&prettier=false&targets=&version=6.26.0&envVersion=
Interestingly, the TypeScript compiler seems to avoid the problem (at least when the constructor function returns undefined) by using super() || this to capture the value used in closures. This was apparently added along with a change to support override values returned by base class constructors in this PR.
Tested in Edge 15 and 16. Apologies if this doesn't repro on ChakraCore's master, or if this is the wrong place to report.