Home Manual Reference Source

source/makeCustomError.js

/**
 * Make a custom error "class".
 *
 * Makes an old style prototype based error class.
 *
 * @example <caption>Typical usage</caption>
 * // In myerrors.js
 * export let MyCustomError = makeCustomError('MyCustomError');
 *
 * // Using the error
 * import {MyCustomError} from './myerrors';
 * throw new MyCustomError('The message');
 *
 * @example <caption>Throwing the error - complete example</caption>
 * try {
 *     throw new MyCustomError('The message', {
 *          code: 'stuff_happened',
 *          details: {
 *              size: 10
 *          }
 *     });
 * } catch(e) {
 *     if(e instanceof MyCustomError) {
 *         console.error(`${e.toString()} -- Code: ${e.code}. Size: ${e.details.size}`);
 *     }
 * }
 *
 * @example <caption>Define an error that extends Error</caption>
 * let NotFoundError = makeCustomError('NotFoundError');
 * // error instanceof NotFoundError === true
 * // error instanceof Error === true
 *
 * @example <caption>Define an error that extends a built in error</caption>
 * let MyValueError = makeCustomError('MyValueError', TypeError);
 * let error = new MyValueError();
 * // error instanceof MyValueError === true
 * // error instanceof TypeError === true
 * // error instanceof Error === true
 *
 * @example <caption>Define an error that extends another custom error</caption>
 * let MySuperError = makeCustomError('MySuperError', TypeError);
 * let MySubError = makeCustomError('MySubError', MySuperError);
 * let error = new MySubError();
 * // error instanceof MySubError === true
 * // error instanceof MySuperError === true
 * // error instanceof TypeError === true
 * // error instanceof Error === true
 *
 * @param {string} name The name of the error class.
 * @param {Error} extendsError An optional Error to extend.
 *      Defaults to {@link Error}. Can be a built in error
 *      or a custom error created by this function.
 * @returns {Error} The created error class.
 */
export default function makeCustomError(name, extendsError) {
    extendsError = extendsError || Error;
    let CustomError = function(message, properties) {
        this.message = message;
        var last_part = new extendsError().stack.match(/[^\s]+$/);
        this.stack = `${this.name} at ${last_part}`;
        if(typeof properties !== 'undefined') {
            Object.assign(this, properties);
        }
    };
    Object.setPrototypeOf(CustomError, extendsError);
    CustomError.prototype = Object.create(extendsError.prototype);
    CustomError.prototype.constructor = CustomError;
    CustomError.prototype.message = "";
    CustomError.prototype.name = name;
    return CustomError;
}