I have an npm module that I have common error handling code in, including a custom error:
function CustomError () { /* ... */ }
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.constructor = CustomError;
module.exports = CustomError;
I have some other modules (let's call them 'module-a' and 'module-b') which both depend on the error handling module.
I also have some code with uses Bluebirds "filtered catch" functionality:
doSomething
.catch(CustomError, () => { /* ... */ });
After some debugging I've discovered (somewhat obviously in hindsight) that errors created in 'module-a' are not instances of errors created by 'module-b'. This is because both modules have their own copy of the JS file containing the CustomError
constructor, which are both run independently.
I would rather not have to resort to my current solution, which is basically:
CustomError.isCustomError = e => e.constructor.toString() === CustomError.toString();
and then:
doSomething
.then(CustomError.isCustomError, () => { /* ... */ });
This is clearly flimsy, and will fall apart if the versions fall out of sync.
Is there some way to ensure that 'module-a' and 'module-b' both use the same instance of the constructor? Or another, less fragile solution.
This is actually a problem in browsers too, when you have an iframe it gets its own copy of, for example, the Array constructor (making instanceof
useless).
The solution for a custom constructor is to duck-type it. Here are some potential solutions with pros and cons.
Check the constructor name. Pro: simple, well-supported. Con: better pick a fairly unique name to avoid false positives and forget about sub-classing it.
Check the properties of the object (e.g. has both 'foo' and 'bar and 'foo' is a function). Pro: mostly fool-proof. Cons: fragile: this check may randomly break if you refactor your custom error class, relatively expensive.
(Recommended) Add a property/method. This is how a number of libraries (for example, moment.js) handle this problem.
Code example:
CustomError.prototype._isCustomError = true;
var isCustomError = function isCustomError(obj) {
return obj instanceof CustomError || Boolean(obj._isCustomError);
};
module.exports = {
CustomError,
isCustomError
};
This is more or less exactly how moment detects whether or not a given object is a moment object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With