Custom error class in TypeScript
Solution 1
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
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
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
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
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')
Kuba T
Updated on June 24, 2021Comments
-
Kuba T about 3 years
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 anHttpRequestError
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: 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?
-
Kuba T almost 9 yearsYeah, my solutions are familiar, the only thing I wondered about is how to extend core classes in the same way as project's ones. Saddly, I don't see any date when TS 1.6 could be released. So, well, I think your solution is the closest to my expectations so far, thanks! :)
-
Benny Neugebauer over 7 yearsIt's worth mentioning that
Object.setPrototypeOf
needs to be called immediately after anysuper(...)
calls. -
Searene over 7 yearsWhy do we need to add
Object.setPrototypeOf(this, FooError.prototype);
? -
Westy92 over 7 yearsI needed to make sure
tsconfig.json
had"target": "es6"
. -
StewartArmbrecht almost 7 yearsYou should be careful with this approach. I thought I read that calling the stack property is EXPENSIVE and should be avoided in your code. I think you might be adding a significant amount of overhead for you custom errors. From the documentation "The string representing the stack trace is lazily generated when the error.stack property is accessed."
-
DarkNeuron over 6 yearsI don't understand why this is necessary in the first place:
this.stack = (<any> new Error()).stack;
Should be inherited from the Error class, yes? -
Estus Flask about 6 yearsBaseError cannot define methods with class syntax, this way they will be replaced with
BaseError.prototype = new Error()
. -
Teoman shipahi over 5 yearsWatch out for Object.setPrototypeOf developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
-
ChetPrickles over 3 years@Searene If you click the "TypeScript breaking changes documentation" link it explains why.
-
Johnathon Sullinger almost 3 yearsYou can get the name without having to define a property on it with the name explicitly hard-coded via
error.constructor.name
. This will return the Type name for you.