🔍

【Nuxt3】useFetchの戻り値の型を得る方法

2023/01/05に公開

useFetchの戻り値の型だけを得たいときってありますよね(あるはず)

TypeScript も 4.9 になりsatisfiesが使えるようになったことでtypeofを使う機会が増えました。そこで、useFetchにおける戻り値の型を取得する方法を提示します。

結論

useFetchの戻り値の型を取得する型は以下の通りです。

type ReturnFetchType<T extends string> = ReturnType<
  typeof useFetch<void, unknown, T>
>["data"];

仕組み

まず、useFetchの型定義を見てみましょう

export declare function useFetch<
  ResT = void,
  ErrorT = FetchError,
  ReqT extends NitroFetchRequest = NitroFetchRequest,
  _ResT = ResT extends void ? FetchResult<ReqT> : ResT,
  Transform extends (res: _ResT) => any = (res: _ResT) => _ResT,
  PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
>(
  request: Ref<ReqT> | ReqT | (() => ReqT),
  opts?: UseFetchOptions<_ResT, Transform, PickKeys>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, ErrorT | null>;

わけがわかりませんね。

では、具体例でみてみましょう。

/api/profileというユーザのプロフィールを返す api があったとします。

const { data } = useFetch("/api/profile");

とした際に、dataの型は以下のようになるとします。

Ref<
  | {
      state: 200;
      data: {
        profile: {
          userId: string;
          displayName: string;
          screenName: string;
          profileImageUrl: string;
        };
      };
    }
  | {
      state: 500;
      data: null;
    }
  | {
      state: 400;
      data: null;
    }
  | null
>;

このとき、useFetch('/api/profile')にカーソルを合わせると、このように表示されます。

const useFetch: <void, FetchError<any>, "/api/profile", {
    state: 200;
    data: {
        profile: {
            userId: string;
            displayName: string;
            screenName: string;
            profileImageUrl: string;
        };
    };
} | {
    state: 500;
    data: null;
} | {
    ...;
}, (res: {
    state: 200;
    data: {
        profile: {
            userId: string;
            displayName: string;
            screenName: string;
            profileImageUrl: string;
        };
    };
} | ... 1 more ... | {
    ...;
}) => {
    state: 200;
    data: {
        profile: {
            userId: string;
            displayName: string;
            screenName: string;
            profileImageUrl: string;
        };
    };
} | ... 1 more ... | {
    ...;
}, KeyOfRes<...>>(request: "/api/profile" | ... 1 more ... | (() => "/api/profile"), opts?:
UseFetchOptions<...> | undefined) => AsyncData<...>

型引数の 3 番目に/api/profileという文字列が現れましたね。どうやら、この第 3 引数にrequestを指定すれば戻り値が得られそうです。

では、結論の型定義をみていきましょう。

type ReturnFetchType<T extends string> = ReturnType<
  typeof useFetch<void, unknown, T>
>["data"];

まず、ReturnTypeは引数に指定した関数の戻り値を返す型です。今回は、useFetchrequestを指定した際の戻り値のAsyncDataを得ることが目的なので使用しています。

次に、typeof useFetch<void, unknown, T>についてですが、まず、typeofで型定義内でuseFetchを扱えるようにします。次に、第 3 引数にrequestを指定します。ここでいうTrequestに該当します。第 1 引数と第 2 引数に関してはなんでもいいので適当にvoidunknownを指定しておきます。

そして、ReturnTypeで得られたAsyncDatadataの中に目的の型があるので、['data']とすることで最終的に目的の型を得ることができます。

実際に使用する際には以下の通りにします。

type Data = ReturnFetchType<"/api/profile">;

Dataにカーソルを合わせると、

Ref<
  | {
      state: 200;
      data: {
        profile: {
          userId: string;
          displayName: string;
          screenName: string;
          profileImageUrl: string;
        };
      };
    }
  | {
      state: 500;
      data: null;
    }
  | {
      state: 400;
      data: null;
    }
  | null
>;

と、しっかり型を得られていることがわかります。ちなみに、Refが要らない場合は

type ReturnFetchType<T extends string> = UnwrapRef<
  ReturnType<typeof useFetch<void, unknown, T>>["data"]
>;

とすることでRefを外せます。

おわりに

それにしてもuseFetchの型定義はすごいですね。

GitHubで編集を提案

Discussion