🍒

try&catchで帰ってくるerrorが全部unknown型だ!? どうするtypescript

2024/01/29に公開

reactでWEBアプリケーションを作成中。try&catchで非同期処理を実装していた時、errorのハンドリングに少し躓いたので備忘録。

この記事で扱うtypescriptのバージョンは4.9.4です

躓いたこと

 try {
   await APIの処理
  } catch (error) {
   setErrorMessage(error.data.message)
  }
type ErrorResponse = {
  status: number;
  data: { message: string; errors: { [k: string]: string[] } };
};

APIでエラーになった場合上記の型のように返ってくるので、エラーのメッセージを保持したい。しかしtry&catchでcatchしたエラーの型はunknownになっている。(APIだけでなくネットワークでどんなエラーが返ってくるかわからないから、一律でunknownになる...?)

とりあえずこの記事を参考にハンドリングをやってみる
https://qiita.com/frozenbonito/items/e708dfb3ab7c1fd3824d

instanseOfを使って、中身を判定しようとしたり、errory用の型を使ってみたがうまくいかず....(この記事ではtypescriptのバージョンが4.3だからかな?)

こういう時は公式だよね

ということでみてみる。

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html#defaulting-to-the-unknown-type-in-catch-variables---useunknownincatchvariables

あった。

Once TypeScript added the unknown type, it became clear that unknown was a better choice than any in catch clause variables for users who want the highest degree of correctness and type-safety, since it narrows better and forces us to test against arbitrary values. Eventually TypeScript 4.0 allowed users to specify an explicit type annotation of unknown (or any) on each catch clause variable so that we could opt into stricter types on a case-by-case basis; however, for some, manually specifying : unknown on every catch clause was a chore.

That’s why TypeScript 4.4 introduces a new flag called useUnknownInCatchVariables. This flag changes the default type of catch clause variables from any to unknown.

TypeScript 4.4から、catchされたエラーはanyからunknownで返されるようになったらしい。

ちなみに、今回躓いた問題への解決策もバッチリ書いてあって、
明示的にエラーをany型で受け取るようにすればできるらしい。

try {
  executeSomeThirdPartyCode();
} catch (err: any) {
  console.error(err.message); // Works again!
}

ちなみに

redux toolkitを使っているので、公式を見てみたらこういうのもあった。

const isApiResponse = (error: unknown): error is ErrorResponse => {
  return (
    typeof error === 'object' &&
    error != null &&
    'status' in error &&
    typeof (error as ApiErrorResponse).status === 'number'
  );
};
 try {
   await APIの処理
  } catch (error) {
    if (isApiResponse(error)) {
      setErrorMessage(error.data.message)
    }
  }

https://redux-toolkit.js.org/rtk-query/usage-with-typescript#inline-error-handling-example

これでもいけました。

ちゃんと型を判定してあげる。

もっと良いエラーハンドリングのやり方があれば知りたい。

Discussion