🤖

【TypeScript】fetchしたデータに型を付与する

2022/11/21に公開

node-fetchなどを使ってfetchしたデータはResponse型で返ってくる。
このとき送られてきたデータにスキーマ情報が含まれていないため、型が不明となってしまう。

const response = await fetch(`${process.env.api}`, {
        headers: {
          Authorization: idToken
        }
      });

こういった場合、クライアント側で受け取ったデータに型情報を付与できるwrap関数を作成する。
ついでにエラーハンドリングも追加。

const fetchWithErrorHandling = <T>(
  url: RequestInfo,
  options: RequestInit
): Promise<T> =>
  fetch(url, options)
    // 1. ネットワーク周りなどのリクエスト以前の段階でのエラーを処理する
    .catch((e) => {
      throw Error(e);
    })
    // 2. サーバサイドで発行されたエラーステータスを処理する
    .then(handleErrors)
    // 3. 以上2つをパスした正常なレスポンスからJSONオブジェクトをパースする
    .then((res) => res?.json());

const handleErrors = async (res: void | Response) => {
  // NOTE: AbortError が発生した場合のみ。res === void に成りうる
  if (!res) return;
  if (res.ok) return res;

  let body: ApiErrorResponse | undefined = undefined;
  try {
    body = await res.json();
  } catch {
    // Non json response
  }

  switch (res.status) {
    case 400:
      throw new ApiRequestError('INVALID_TOKEN', body);
    case 401:
      throw new ApiRequestError('UNAUTHORIZED', body);
    case 403:
      throw new ApiRequestError('FORBIDDEN', body);
    case 500:
      throw new ApiRequestError('INTERNAL_SERVER_ERROR', body);
    case 502:
      throw new ApiRequestError('BAD_GATEWAY', body);
    case 404:
      throw new ApiRequestError('NOT_FOUND', body);
    default:
      throw new ApiRequestError('UNHANDLED_ERROR', body);
  }
};

こんな感じで使う

type MyDataType = {
    id: number;
    name: string;
}

const response = await fetchWithErrorHandling<MyDataType>(`${process.env.api}`, {
        headers: {
          Authorization: idToken
        }
      });

Discussion