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:
class ErrorClass extends Error {
constructor (message) {
super();
if (Error.hasOwnProperty('captureStackTrace'))
Error.captureStackTrace(this, this.constructor);
else
Object.defineProperty(this, 'stack', {
value: (new Error()).stack
});
Object.defineProperty(this, 'message', {
value: message
});
}
}
Then extend that class instead:
class FooError extends ErrorClass {
constructor(message) {
super(message);
}
}
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:
_get(Object.getPrototypeOf(FooError.prototype), "constructor", this).call(this, message)
Where _get is a helper function injected into the script:
(function get(object, property, receiver) {
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get(parent, property, receiver);
}
} else if ("value" in desc) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
});
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 to this
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 new Error
which isn't assigned to anything.
If we use the ErrorClass
defined above, it does adhere to the class structure as expected by Babel.