Create custom Class that extends from Error in TypeScript

avatar

Borislav Hadzhiev

Last updated: Feb 26, 2022

banner

Photo from Unsplash

Create custom Class that extends from Error in TypeScript #

To create a custom class that extends from Error:

  1. Define a new class that extends from the Error object.
  2. Use the super() method in the classes' constructor.
  3. Manually adjust the prototype of the new class.
index.ts
export class CustomError extends Error { statusCode = 400; constructor(message: string) { super(message); // 👇️ because we are extending a built-in class Object.setPrototypeOf(this, CustomError.prototype); } getErrorMessage() { return 'Something went wrong: ' + this.message; } } const err = new CustomError('Failed to fetch'); // 👇️ "Failed to fetch" console.log(err.message); console.log(err.statusCode); // 👉️ 400 // 👇️ "Something went wrong: Failed to fetch" console.log(err.getErrorMessage()); // ✅ Use type guard to be able to access properties/methods if (err instanceof CustomError) { console.log(err.statusCode); // 👉️ 400 // 👇️ "Something went wrong: Failed to fetch" console.log(err.getErrorMessage()); }

We created a CustomError class that extends from Error.

Whenever you extend a class, you have to call super() before being able to use the this keyword.

We also had to use the Object.setPrototypeOf method, because we are extending a built-in class.

You have to call Object.setPrototypeOf immediately after calling super().

You have to use this approach for any classes that extend built-ins and for any of the subclasses of CustomError.

We are basically manually adjusting the prototype. If you want to read more on why this is needed, check out this section of TypeScript's wiki.

You have to use the instanceof operator if you need to check if a variable stores an instance of CustomError.

index.ts
export class CustomError extends Error { statusCode = 400; constructor(message: string) { super(message); // 👇️ because we are extending a built-in class Object.setPrototypeOf(this, CustomError.prototype); } getErrorMessage() { return 'Something went wrong: ' + this.message; } } const err = new CustomError('Failed to fetch'); // ✅ Check if instance of CustomError if (err instanceof CustomError) { console.log(err.statusCode); console.log(err.getErrorMessage()); }

The instanceof operator serves as a type guard.

If you throw a CustomError in some other place in your code, you need a way to check if the caught error is a CustomError before you are able to access CustomError specific properties and methods.

This works in the same way as you would check if an error is an instance of the Error object in a catch block.

index.ts
async function getData() { try { await Promise.resolve(24); } catch (err) { // 👉️ err is unknown here // can't access Error specific properties if (err instanceof Error) { console.log(err.message); // 👈️ err is now Error } console.log('Unexpected error: ', err); } }

The err variable has a type of unknown in the catch block, so we have to the instanceof operator before we are able to access the message property.

This is needed, because there's no way to be sure that the caught error will be of specific type ahead of time.

Note that any classes that subclass CustomError also need to manually adjust the prototype.
I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.