When running this snippet through BabelJS:
class FooError extends Error {
constructor(message) {
super(message);
}
}
let error = new FooError('foo');
console.log(error, error.message, error.stack);
it outputs
{}
which is not what I expect. Running
error = new Error('foo');
console.log(error, error.message, error.stack);
produces
{} foo Error: foo
at eval (eval at <anonymous> (https://babeljs.io/scripts/repl.js?t=2015-05-21T16:46:33+00:00:263:11), <anonymous>:24:9)
at REPL.evaluate (https://babeljs.io/scripts/repl.js?t=2015-05-21T16:46:33+00:00:263:36)
at REPL.compile (https://babeljs.io/scripts/repl.js?t=2015-05-21T16:46:33+00:00:210:12)
at Array.onSourceChange (https://babeljs.io/scripts/repl.js?t=2015-05-21T16:46:33+00:00:288:12)
at u (https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js:28:185)
which is exactly what I would like from the extended error.
My goal is to extend Error
into a variety of subclasses and use them in bluebird's catch
matching. So far, that is failing miserably.
Why is the subclass not showing a message or stack trace?
Edit: using Chrome's built-in subclassing (thanks to @coder) works perfectly. This isn't specific to Babel, necessarily, as the following example (from @loganfsmyth on Babel's gitter feed) shows:
// Works
new (function(){
"use strict";
return class E extends Error { }
}());
// Doesn't
new (function(){
"use strict";
function E(message){
Error.call(this, message);
};
E.prototype = Object.create(Error);
E.prototype.constructor = E;
return E;
}());
This is a limitation due to the downlevel compilation of ES6 to ES5. Find more about this in TypeScript's explanation.
As a workaround you can do:
In some cases cases
Object.setPrototypeOf(this, FooError.prototype);
might be enough.You'll find more information in the corresponding Github issue and the
In short, extending using babel's transpiled code only works for classes built in a specific way, and a lot of native stuff doesn't appear to be built like that. Babel's docs warns that extending many native classes doesn't work properly.
You could create a buffer class that creates the properties "manually", something like this:
Then extend that class instead:
Why doesn't it work as you'd expect?
If you look at what is transpiled, you'll see that babel first assigns a copy of the super class' prototype to the sub class, then when you call
new SubClass()
this function is called:Where _get is a helper function injected into the script:
it does something like finds the
constructor
property descriptor of the sub class' prototype's prototype and tried to call its getter with the new subclass instance as context if it exists or return its value (if ("value" in desc)
), in this case the Error constructor itself. It doesn't assign anything tothis
from the super call so while the new object has the right prototype, it didn't get constructed the way you expect. Basically the super call does nothing to the newly constructed object, just creates a newError
which isn't assigned to anything.If we use the
ErrorClass
defined above, it does adhere to the class structure as expected by Babel.