type wrangling for a custom `$fetch` wrapper in nuxt 3

so i tried the other day to create a custom wrapper for $fetch in nuxt 3. i hate the whole difference between useFetch and $fetch, so i thought i could unify it and switch between them based on whether or not we're in the setup function.

for those blissfully unaware, nuxt 3 requires usage of useFetch in setup functions, and $fetch when performing actions outside of it.

$fetch (and useFetch) are very useful in nuxt 3 because they copy types from the nitro routes. but, it's difficult to make a custom wrapper with this functionality.

this is what i came up with:

interface MyFetch<
  DefaultT = unknown,
  DefaultR extends NitroFetchRequest = NitroFetchRequest
> {
  <
    T = DefaultT,
    R extends NitroFetchRequest = DefaultR,
    O extends NitroFetchOptions<R> = NitroFetchOptions<R>
  >(
    request: R,
    opts?: O
  ): Promise<
  // @ts-ignore
    TypedInternalResponse<
      R,
      T,
      NitroFetchOptions<R> extends O ? "get" : ExtractedRouteMethod<R, O>
    >
  >;
}

const $myFetch: MyFetch = async (request, opts) => {
  ...
}

there are a few caveats:

  • // @ts-ignore because vscode's type checker can't compare excess stack depths or smth
  • it's difficult to make the types work out in your function, so i used as any a few times

otherwise, it all works! the types outside of this function work perfectly.