Custom error class in TypeScript

InheritanceError HandlingTypescript

Inheritance Problem Overview


I'd like to create my own error class in TypeScript, extending core Error to provide better error handling and customized reporting. For example, I want to create an HttpRequestError class with url, response and body passed into its constructor, which reponds with Http request to http://example.com failed with status code 500 and message: Something went wrong and proper stack trace.

How to extend core Error class in TypeScript? I've already found post in SO: https://stackoverflow.com/questions/12915412/how-do-i-extend-a-host-object-e-g-error-in-typescript but this solution doesn't work for me. I use TypeScript 1.5.3

Any ideas?

Inheritance Solutions


Solution 1 - Inheritance

TypeScript 2.1 had a breaking changes regarding Extending built-ins like Error.

From the TypeScript breaking changes documentation

class FooError extends Error {
    constructor(msg: string) {
        super(msg);

        // Set the prototype explicitly.
        Object.setPrototypeOf(this, FooError.prototype);
    }

    sayHello() {
        return "hello " + this.message;
    }
}

Then you can use:

let error = new FooError("Something really bad went wrong");
if(error instanceof FooError){
   console.log(error.sayHello());
}

Solution 2 - Inheritance

Until 1.6 rolls around, I've just been making my own extendable classes.

class BaseError {
	constructor () {
		Error.apply(this, arguments);
	}
}

BaseError.prototype = new Error();

class HttpRequestError extends BaseError {
	constructor (public status: number, public message: string) {
		super();	
	}
}

var error = new HttpRequestError(500, 'Server Error');

console.log(
	error,
	// True
	error instanceof HttpRequestError,
	// True
	error instanceof Error
);

Solution 3 - Inheritance

I am using TypeScript 1.8 and this is how I use custom error classes:

UnexpectedInput.ts

class UnexpectedInput extends Error {

  public static UNSUPPORTED_TYPE: string = "Please provide a 'String', 'Uint8Array' or 'Array'.";

  constructor(public message?: string) {
    super(message);
    this.name = "UnexpectedInput";
    this.stack = (<any> new Error()).stack;
  }

}

export default UnexpectedInput;

MyApp.ts

import UnexpectedInput from "./UnexpectedInput";

...

throw new UnexpectedInput(UnexpectedInput.UNSUPPORTED_TYPE);

For TypeScript versions older than 1.8, you need to declare Error:

export declare class Error {
  public message: string;
  public name: string;
  public stack: string;
  constructor(message?: string);
}

Solution 4 - Inheritance

For Typescript 3.7.5 this code provided a custom error class that also captured the correct stack information. Note instanceof does not work so I use name instead

// based on https://gunargessner.com/subclassing-exception

// example usage
try {
  throw new DataError('Boom')
} catch(error) {
  console.log(error.name === 'DataError') // true
  console.log(error instanceof DataError) // false
  console.log(error instanceof Error) // true
}

class DataError {
  constructor(message: string) {
    const error = Error(message);

    // set immutable object properties
    Object.defineProperty(error, 'message', {
      get() {
        return message;
      }
    });
    Object.defineProperty(error, 'name', {
      get() {
        return 'DataError';
      }
    });
    // capture where error occured
    Error.captureStackTrace(error, DataError);
    return error;
  }
}

There are some other alternatives and a discussion of the reasons.

Solution 5 - Inheritance

There is a neat library for this at https://www.npmjs.com/package/ts-custom-error

ts-custom-error allow you to create error custom Error very easily:

import { CustomError } from 'ts-custom-error'
 
class HttpError extends CustomError {
    public constructor(
        public code: number,
        message?: string,
    ) {
        super(message)
    }
}

usage:

new HttpError(404, 'Not found')

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKuba TView Question on Stackoverflow
Solution 1 - InheritancezivView Answer on Stackoverflow
Solution 2 - InheritancethoughtrepoView Answer on Stackoverflow
Solution 3 - InheritanceBenny NeugebauerView Answer on Stackoverflow
Solution 4 - InheritancePeterView Answer on Stackoverflow
Solution 5 - InheritanceHugo GresseView Answer on Stackoverflow