Can I define custom types for user-defined exceptions in JavaScript? If so, how would I do it?
In short:
If you are using ES6 without transpilers:
class CustomError extends Error { /* ... */}
See Extending Error in Javascript with ES6 syntax for what's the current best practice
If you are using Babel transpiler:
Option 1: use babel-plugin-transform-builtin-extend
Option 2: do it yourself (inspired from that same library)
function CustomError(...args) {
const instance = Reflect.construct(Error, args);
Reflect.setPrototypeOf(instance, Reflect.getPrototypeOf(this));
return instance;
}
CustomError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
Reflect.setPrototypeOf(CustomError, Error);
If you are using pure ES5:
function CustomError(message, fileName, lineNumber) {
const instance = new Error(message, fileName, lineNumber);
Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
return instance;
}
CustomError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
if (Object.setPrototypeOf){
Object.setPrototypeOf(CustomError, Error);
} else {
CustomError.__proto__ = Error;
}
Alternative: use Classtrophobic framework
Explanation:
Why extending the Error class using ES6 and Babel is a problem?
Because an instance of CustomError is not anymore recognized as such.
class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false
In fact, from the official documentation of Babel, you cannot extend any built-in JavaScript classes such as Date, Array, DOM or Error.
The issue is described here:
What about the other SO answers?
All the given answers fix the instanceof issue but you lose the regular error console.log:
console.log(new CustomError('test'));
// output:
// CustomError {name: "MyError", message: "test", stack: "Error↵ at CustomError (:4:19)↵ at :1:5"}
Whereas using the method mentioned above, not only you fix the instanceof issue but you also keep the regular error console.log:
console.log(new CustomError('test'));
// output:
// Error: test
// at CustomError (:2:32)
// at :1:5