Skip to content

Unexpected super() return value when subclassing ES5 ctor function #4663

Closed
@bryanrsmith

Description

@bryanrsmith

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 this

It 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 this
function A() { return { test: true }; }

// class B as above

new B(): // does not throw
class A { constructor() { return 'test'; }}

// class B as above

new B(): // also does not throw when A is a class instead of ES5 constructor function

Chrome, 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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions