Last Updated: October 15, 2020
·
4.092K
· pornel

Subclassing Error in JavaScript is harder than it seems

Unfortunately Error() function in JS is not a typical constructor and standard methods with Error.call(this) or Error.apply(this) will not work correctly. From the spec:

15.11.1 The Error Constructor Called as a Function

When Error is called as a function rather than as a constructor, it creates and initialises a new Error object. Thus the function call Error(…) is equivalent to the object creation expression new Error(…) with the same arguments.

The next best thing you can do is to pretend to subclass it and then copy properties you want:

function HttpError(code, msg) {
    this.message = msg;
    this.statusCode = code;
    this.name = 'HttpError';
    const err = Error(msg); // http://es5.github.io/#x15.11.1
    this.stack = err.stack;
}

HttpError.prototype = Object.create(Error.prototype);
HttpError.prototype.constructor = HttpError;

The code above passes these tests:

const err = new HttpError(404, "Test");

assert(err instanceof Error);
assert(err instanceof HttpError);
assert.equal(err.name, 'HttpError');
assert.equal(err.statusCode, 404);
assert(util.isError(err));
// These would fail if you relied on Error.call(this, msg)
assert.include(err.stack, __filename);
assert.equal(err.message, 'Test');