🚀Understanding Custom Errors in TypeScript: A Complete Guide (2025) 👍

The Developer Life
3 min readJan 2, 2025

--

Error handling is a crucial aspect of building robust applications, and TypeScript, with its powerful type system, makes it even more streamlined. However, when working with custom errors in TypeScript, developers sometimes encounter issues, especially when using instanceof to differentiate between error types.

In this article, we’ll dive deep into how to create and handle custom errors in TypeScript effectively. If you’ve ever run into issues with instanceof not working as expected with your custom error classes, this guide is for you.

Why Custom Errors?

Before jumping into the implementation, let’s briefly discuss why you might want to use custom errors.

In many applications, errors are more than just an indication that “something went wrong.” They can carry specific information about the nature of the failure, allowing the application to handle different kinds of errors in different ways. Custom errors let you create distinct error types that are semantically meaningful and easily distinguishable.

Defining a Custom Error in TypeScript

To define a custom error in TypeScript, you need to extend the built-in Error class. However, there are some nuances you need to be aware of, particularly around setting up the prototype chain correctly.

Here’s how to define a custom error:

class CustomError extends Error {
constructor(message: string) {
super(message); // Call the constructor of the base class `Error`
this.name = "CustomError"; // Set the error name to your custom error class name
// Set the prototype explicitly to maintain the correct prototype chain
Object.setPrototypeOf(this, CustomError.prototype);
}
}

Key Points to Note:

  • Super Call: The super(message) call invokes the constructor of the Error class, ensuring that the error message is correctly passed and accessible via err.message.
  • Error Name: Setting this.name to the name of your custom error class makes the error type clear when inspecting stack traces or logs.
  • Prototype Chain: The most critical step is setting the prototype chain correctly using Object.setPrototypeOf(this, CustomError.prototype). This ensures that instanceof checks work as expected, which is particularly important when TypeScript is transpiled to ES5.

Throwing a Custom Error

Once you have your custom error class, throwing an error is straightforward:

function someFunction() {
throw new CustomError("This is a custom error");
}ty

Catching and Identifying the Custom Error

Now, let’s see how you can catch this custom error and check its type using instanceof:

try {
someFunction();
} catch (err) {
if (err instanceof CustomError) {
console.log("Caught a CustomError:", err.message);
} else {
console.log("Caught a different error:", err);
}
}

Why instanceof Might Not Work

If you’ve tried the above and found that instanceof wasn't working, here are some potential reasons:

  1. Prototype Chain Issues: If the prototype chain isn’t correctly maintained (e.g., due to how the class is transpiled or how it’s instantiated), instanceof might fail. This is why explicitly setting the prototype with Object.setPrototypeOf is crucial.
  2. Cross-Realm Issues: If the error originates from a different JavaScript realm (such as a different window or an iframe in a browser), instanceof might fail because the Error object is different in each realm.
  3. Transpilation Problems: Ensure your TypeScript is correctly configured and transpiled. Problems may arise if your TypeScript configuration (like target) or Babel setup doesn’t handle ES6 classes correctly.

Best Practices

  • Always set the prototype chain: This is essential to ensure instanceof works correctly.
  • Use meaningful error names: This helps with debugging and log analysis.
  • Document your errors: Make sure that your team knows what kinds of custom errors exist and what they represent.

Conclusion

Custom errors in TypeScript are a powerful tool for making your error handling more expressive and tailored to your application’s needs. By correctly setting up your custom error classes and ensuring the prototype chain is maintained, you can leverage the full power of TypeScript’s type system and JavaScript’s runtime behavior to create robust, maintainable applications.

Next time you encounter an issue with instanceof not working as expected, remember to check your prototype chain, and you’ll be back on track in no time.

Happy coding! đź’»

--

--

No responses yet