How do you use typed errors in async catch()

This error has nothing to do with async. You can't have typed catch variables.

The reason for this is simple: the types in TypeScript only exist until the code is compiled. Once it's compiled, all you've got is typeless JavaScript.

Having type filters on catch clauses would require checking the errors' types at runtime, and there's simply no reliable way to do that, so I would say such a feature is unlikely to ever be supported.


You cannot assign a custom type to your error directly but you can use a type guard. A type guard is a function which helps TypeScript's compiler to figure out the type of your error.

Writing a type guard with a type predicate is very easy. You just need to implement a boolean check which accepts any value and figures out if this value has a property of your custom type.

Given your example, I can see that your ApiError has a custom property called code, so a type guard could look like this:

function isApiError(x: any): x is ApiError {
  return typeof x.code === 'number';
}

Note the x is ApiError return type. That's a type predicate!

Using the isApiError function from above, it will be possible now for TypeScript to infer your custom error type:

interface ApiError {
  code: number;
  error: string;
}

async function test() {
  const isApiError = (x: any): x is ApiError => {
    return typeof x.code === 'number';
  };

  try {
    return await api();
  } catch (error) {
    if (isApiError(error)) {
      // Thanks to the type guard, TypeScript knows know what "error" is
      console.log(error.code);
    }
  }
}

You can see a type guard in action here: https://www.youtube.com/watch?v=0GLYiJUBz6k


In TypeScript, catch clause variables may not have a type annotation (aside from, as of TypeScript 4.0, unknown). This is not specific to async. Here's an explanation from Anders Hejlsberg:

We don't allow type annotations on catch clauses because there's really no way to know what type an exception will have. You can throw objects of any type and system generated exceptions (such as out of memory exception) can technically happen at any time.

You can check for the existence of error.code and error.message properties (optionally using a user-defined type guard) in the catch body.

Tags:

Typescript