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

Extending builtins like Error and Array doesn't work in 6.x #3083

Closed
jacogr opened this issue Nov 16, 2015 · 4 comments
Closed

Extending builtins like Error and Array doesn't work in 6.x #3083

jacogr opened this issue Nov 16, 2015 · 4 comments
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue

Comments

@jacogr
Copy link

jacogr commented Nov 16, 2015

Code

const defineError = function(name) {
  return class extends Error {
    constructor(message) {
      super();

      this.message = message;
      this.name = name;
    }
  };
};

const ErrorA = defineError('ErrorA');

console.log('new ErrorA() instanceof Error = ', new ErrorA() instanceof Error);
console.log('new ErrorA() instanceof ErrorA = ', new ErrorA() instanceof ErrorA);

Babel ^5.8.21

package.json:

{
  "name": "babel-instanceof",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "node_modules/.bin/babel index.js -o compiled.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "babel": "^5.8.21",
    "babel-core": "^5.8.21"
  }
}

.babelrc

{
  "stage": 1
}

output:

new ErrorA() instanceof Error =  true
new ErrorA() instanceof ErrorA =  true

^6.1.4

package.json:

{
  "name": "babel-instanceof",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "node_modules/.bin/babel index.js -o compiled.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "babel-core": "^6.1.4",
    "babel-cli": "^6.1.4",
    "babel-preset-es2015": "^6.1.4",
    "babel-preset-stage-1": "^6.1.4"
  }
}

.babelrc

{
  "presets": ["es2015", "stage-1"],
}

output:

new ErrorA() instanceof Error =  true
new ErrorA() instanceof ErrorA =  false
@babel-bot
Copy link
Collaborator

Comment originally made by @loganfsmyth on 2015-11-19T08:57:02.000Z

Extending builtin types like Array and Error was never supported in Babel 5 either, it just didn't fail in quite the same way.


Comment originally made by @jacogr on 2015-11-19T15:51:56.000Z

Well, yes... "unsupported" but the reality is that you only go find that out when things don't work. So in Babel 5, nobody bothered since the basic use-case did what it was supposed to.

Despite that, a regression is a regression, the behaviour has changed between the versions, you would expect a class to show as it's own instanceof despite the parent,


Comment originally made by @loganfsmyth on 2015-11-19T17:03:45.000Z

@jacogr

you would expect a class to show as it's own instanceof despite the parent,

Unfortunately, what the Error class constructor essentially does is this:

class Error {
    constructor(){
        // the 'this' here would be your `MyError`

        // Ignores `this` and returns an entirely new Error
        return new Error();
    }
}
class MyError extends Error {}
var e = new MyError();

It worked in Babel 5 because Babel did not support a class constructor returning a value in the spec-given way.

I do have an alternate approach for you though. Do this:


function ExtendableBuiltin(cls){
    function ExtendableBuiltin(){
        cls.apply(this, arguments);
    }
    ExtendableBuiltin.prototype = Object.create(cls.prototype);
    Object.setPrototypeOf(ExtendableBuiltin, cls);

    return ExtendableBuiltin;
}

and use that in your example as:

const defineError = function(name) {
  return class extends ExtendableBuiltin(Error) {
    constructor(message) {
      super();

      this.message = message;
      this.name = name;
    }
  };
};

Comment originally made by @loganfsmyth on 2015-11-19T17:05:48.000Z

I'd still not recommend extending builtins like this, but it will make the code behave like it did in Babel 5.x


Comment originally made by @loganfsmyth on 2016-07-08T04:37:29.000Z

Old news by now, but posting in here so people can find it. All of the logic I mention above is wrapped up and available in https://www.npmjs.com/package/babel-plugin-transform-builtin-extend as an easy-to-use package.

@babel-bot babel-bot changed the title class extends - different behaviour between 5 & 6 Extending builtins like Error and Array doesn't work in 6.x Sep 7, 2016
vzvu3k6k added a commit to vzvu3k6k/js-daichkr-client that referenced this issue Nov 29, 2016
`(new HTTPError()) instanceof HTTPError` was false because
babel-plugin-transform-es2015-classes doesn't support extending of
built-in classes.

- https://babeljs.io/docs/plugins/transform-es2015-classes/
- babel/babel#3083
- http://stackoverflow.com/a/33877501

To fix this issue, This commit removes babel-preset-es2015 except for
transform-es2015-modules-commonjs. The current LTS version of nodejs is
v6.9.1 and it supports most of es2015 features according to
http://node.green/.
davidyaha added a commit to accounts-js/accounts that referenced this issue Feb 5, 2017
davidyaha added a commit to accounts-js/accounts that referenced this issue Feb 5, 2017
maxkoryukov added a commit to route4me/route4me-nodejs-sdk that referenced this issue Mar 11, 2017
* several files renames (to make the sources more understandable)
* add `builtin` package for babel (see babel/babel/issues/3083 )
* switch testing to the DIST version of package (not sources)
* probably fix the problems in browser testing (`instance of` now works), see #49
@xpl
Copy link

xpl commented Jul 15, 2017

Try this as a workaround:

class DDoSProtectionError extends Error {
    constructor () {
        super ()
        // a workaround to make `instanceof DDoSProtectionError` work in ES5
        this.constructor = DDoSProtectionError 
        this.__proto__   = DDoSProtectionError.prototype
    }
}

@perekrestov-igor
Copy link

class DDoSProtectionError extends Error {
    constructor () {
        super ()
        // a workaround to make `instanceof DDoSProtectionError` work in ES5
        this.constructor = DDoSProtectionError 
        //this.__proto__   = DDoSProtectionError.prototype
    }
}
//For IE too
DDoSProtectionError.prototype = Error.prototype;

@avesus
Copy link

avesus commented Oct 16, 2017

@xpl you saved my day! It's the only working solution.

UnicodeSnowman added a commit to UnicodeSnowman/stitch-js-sdk that referenced this issue Nov 14, 2017
* Add `babel-plugin-transform-builtin-extend`
* Subclassing builtin types needs special treatment by babel
  * Without this plugin, in a node environment, a subclass of Error does not actually behave like a true subclass, which manifests itself via a missing stacktrace when a StitchError is thrown

More details [here](babel/babel#3083)
UnicodeSnowman added a commit to UnicodeSnowman/stitch-js-sdk that referenced this issue Nov 14, 2017
* Add `babel-plugin-transform-builtin-extend`
* Subclassing builtin types needs special treatment by babel
  * Without this plugin, in a node environment, a subclass of Error does not actually behave like a true subclass, which manifests itself via a missing stacktrace when a StitchError is thrown

More details [here](babel/babel#3083)
UnicodeSnowman added a commit to UnicodeSnowman/stitch-js-sdk that referenced this issue Nov 14, 2017
* Add `babel-plugin-transform-builtin-extend`
* Subclassing builtin types needs special treatment by babel
  * Without this plugin, in a node environment, a subclass of Error does not actually behave like a true subclass, which manifests itself via a missing stacktrace when a StitchError is thrown

More details [here](babel/babel#3083)
UnicodeSnowman added a commit to UnicodeSnowman/stitch-js-sdk that referenced this issue Nov 14, 2017
* Add `babel-plugin-transform-builtin-extend`
* Subclassing builtin types needs special treatment by babel
  * Without this plugin, in a node environment, a subclass of Error does not actually behave like a true subclass, which manifests itself via a missing stacktrace when a StitchError is thrown

More details [here](babel/babel#3083)
UnicodeSnowman added a commit to UnicodeSnowman/stitch-js-sdk that referenced this issue Nov 15, 2017
* Add `babel-plugin-transform-builtin-extend`
* Subclassing builtin types needs special treatment by babel
  * Without this plugin, in a node environment, a subclass of Error does not actually behave like a true subclass, which manifests itself via a missing stacktrace when a StitchError is thrown

More details [here](babel/babel#3083)
richvdh added a commit to matrix-org/matrix-js-sdk that referenced this issue Nov 22, 2017
We were relying on being able to override toString in DecryptionError, which
(a) doesn't work thanks to babel/babel#3083, and (b)
was a bit naughty anyway. Instead, just add a detailedString property and use
that.
@lock lock bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label May 4, 2018
@lock lock bot locked as resolved and limited conversation to collaborators May 4, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue
Projects
None yet
Development

No branches or pull requests

5 participants