Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
bryanrsmith opened this issue Feb 9, 2018 · 4 comments
Closed

Comments

@bryanrsmith
Copy link

bryanrsmith commented Feb 9, 2018

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.

@sethbrenith
Copy link
Contributor

sethbrenith commented Feb 9, 2018

Thanks for the detailed report!

Notes and links: Super calls Construct, which should return NormalCompletion(thisArgument) if the base constructor didn't return an object.

@JSteunou
Copy link

Hi guys, I still have this issue on Edge/17.17134

Is this bug back or the fix not shipped yet?

@sethbrenith
Copy link
Contributor

This bug is fixed in Edge version 18.17763 (the fall 2018 release). @JSteunou you still have the version from spring of this year. I can't say when exactly you would get the update automatically, but according to this page, you can get the update immediately if you manually check for updates.

@JSteunou
Copy link

Thank you for the quick answer @sethbrenith 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants