https://zenn.dev/takepepe/articles/fetch-error-convolution

og-base_z4sxah.png

「データ取得で try...catch」とは、以下の様なものを指します。

try {
  const data = await fetchSomething();
  // 正常系レスポンスの処理
} catch (err) {
  if (isFetchError(err)) {
    // 異常系レスポンスの処理
  }
}

理由はつぎのとおりです。

要約すると、データ取得時は常にこの様に書きたい、という話です。useSWR・useQuery や apollo/client でお馴染みのインターフェイスです。

const { data, err, status } = await fetchSomething();
if (data) // 正常系レスポンスの処理
if (err) // 異常系レスポンスの処理

レスポンスを型定義で表すと、この様なものになります。

type Res<T, K> = {
  data?: T;
  err?: K;
  status: number;
};

eslint の no-unused-expressions で以下のミスはすぐに気付きますが、any に握りつぶされている中間コードがもしあれば、catch 行きになる可能性が拭いきれません。

try {
  const data = await fetchSomething();
  // 参照ミスなどで例外がthrowされる
  a.b.c;
} catch (err) {
  if (isFetchError(err)) {
    // 異常系レスポンスの処理
  }
  // ReferenceError でここに着地する
}

こういった、データ取得とは関係ない例外と同列で catch 句ハンドリングしてしまうと、catch 句の肥大化につながりかねません。HttpError は開発者にとって想定範囲内なので、データ取得関数内部で整形し、畳み込んでおきたいです。

理由としてはこれが一番大きいです。データ取得関数が全てResの様なレスポンスを返すことが確約されていれば、

Promise.all での取り回しが格段に楽になります。