Handling errors like a pro in TypeScript

Kolby Sisk
Udacity Eng & Data
Published in
5 min readDec 21, 2022

--

Error handling in Type/JavaScript is a topic that doesn’t get the importance it deserves. It’s crucial to the longevity of any project to catch and log errors.

As I’ve started working with TypeScript more over the years, I started to realize that I didn’t really understand error handling. I would often run into this problem:

error is type unknown, so we can’t perform any actions with error until we cast it to a new type, or narrow the type. The correct answer is to narrow the type, and we’ll look at how to do that, but why is this even necessary?

In JavaScript, just about anything can be thrown:

So the error that is caught truly is unknown. But, there are ways we can handle errors cleanly with TypeScript, and over the years I’ve developed a design pattern that I really enjoy using to help me do just that.

First, the basics of errors in JavaScript

Types of errors in JavaScript

There are many types of errors in JavaScript, but the most common are:

  • ReferenceError — The code referenced a variable that doesn’t exist.
  • TypeError — A value wasn’t the expected type.
  • SyntaxError — The code was syntactically invalid.

Throwing errors

There are times when you should throw an error manually. For example, you might have some code that relies on a value being returned from a function call, but there’s a possibility of the value being undefined, or at least TypeScript believes there is. In this example throwing is the best solution to narrow the user that is returned.

Catching errors

Once an error is thrown, it will bubble up the callstack until caught in a try/catch statement. When code that is run inside of a try block throws an error, it will be “caught” in the catch block. The error can originate from a function nested inside of a function, and will bubble up until caught.

Narrowing the type of error

Once caught, it can be useful to check the type of error that was thrown. This allows us to narrow the type from unknown, to a specific type that we can then interact with. We can do that with instanceof.

Enough of the basics, let’s look at the design pattern

In my latest project I grouped my code by domains in directories named Features. I’ll go over this architecture in detail in another post, but TL;DR is that a Feature dir contains code for a given domain. It can contain related components, hooks, types, errors, and more. What we’re interested in for this post are the errors. Each Feature dir contains an errors.ts file where I define a custom error class for the respective domain.

Creating a custom error type

In my errors.ts file I export a class. I maintain a union type for the potential names, which adds some nice intellisense and type safety. The class extends the Error object, which allows a stack trace to be inserted (for most JS runtimes).

Throwing a custom error

When a new error is instantiated, the name value has intellisense and must be one of the names defined in the union type.

Catching a custom error

When the error is caught we can narrow the error type by using instanceof. Once narrowed, error.name gives us intellisense. At this point we can perform logic based on the name of the error that was thrown. In this example the PROJECT_LIMIT_REACHED error is one we want to show the user, and we provided a message specifically to be rendered for the user.

Making a reusable error base

Since I have many errors.ts files, I want to ensure my code stays DRY. The only dynamic code in our class is the union type of names. So I create an ErrorBase class, which accepts a generic that is used as the name type.

Now, when I create a new custom error class I can extend this base, and all I need to do is give it the union type of available names.

Conclusion

I really enjoy this design pattern and my code is much easier to maintain as a result. Keep in mind that handling errors is only part of a well maintained app, another important step is logging the errors using something like Sentry.

I hope you learned something new, and if you want to learn more make sure to follow me here and on Twitter @Kolbysisk. 🙏

--

--

Builder of software with a passion for learning. I specialize in web development and user experience design. www.kolbysisk.com