DEV Community

Cover image for Handling Exceptions In TypeScript
Dan Fletcher
Dan Fletcher

Posted on • Updated on

Handling Exceptions In TypeScript

TypeScript is all about type safety. But there are a number of situations that TypeScript can't properly guard against without a little help.

Take Exceptions for example. When we wrap a try .. catch around some code to handle a potential exception we probably want to do something like this:

try {
  await this.userService.all();
} catch (e: Error) {
  this.errorService.handle(e);
}
Enter fullscreen mode Exit fullscreen mode

Unfortunately TypeScript won't allow you to do this!

The issue is that in JavaScript (and TypeScript) anything can be thrown as an "error". You can throw any arbitrary type; a number, a string, even null.

This is totally valid JavaScript and TypeScript:

throw 42;
Enter fullscreen mode Exit fullscreen mode

Which means that our try .. catch only has two options for the type hint here. any or unknown.

The any type is the escape hatch out of TypeScript's type safety so we generally want to avoid that if we can help it.

So we're left with unknown.

The unknown type in TS is a way to force users of the type, to narrow the type down to something specific. It's not valid to use something when the type is unknown so we're forced to write a Type Guard.

Here is the try .. catch from above rewritten to use unknown:

try {
  await this.userService.all();
} catch (e: unknown) {
  if (e instanceof Error) {
    // guaranteed to be an Error now!
    this.errorService.handle(e);
  } else {
    throw Error("Can't handle this error!");
  }
}
Enter fullscreen mode Exit fullscreen mode

There is a cleaner way to do this though. What if the handle method dealt with the unknown type instead?

class ErrorService {
  handle(e: unknown) {
    let message: string;

    if (e instanceof Error) {
      message = e.message;
    } else if (typeof e === 'string') {
      message = e;
    } else {
      message = "We don't know what the heck happened -- sorry!"
    }

    // handle the error message here
  }
}
Enter fullscreen mode Exit fullscreen mode

This way the try..catch outside can just pass the unknown error through like this:

try {
  await this.userService.all();
} catch (e: unknown) {
  this.errorService.handle(e);
}
Enter fullscreen mode Exit fullscreen mode

Like what you read? Want to support me?

A cup of coffee goes a long way 🙏

Why not buy me one? https://ko-fi.com/danjfletcher

Latest comments (0)