nuxt / nuxt

The Intuitive Vue Framework.

Home Page:https://nuxt.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Custom useFetch type error

jxk-developer opened this issue · comments

Environment

  • Operating System: Darwin
  • Node Version: v20.11.1
  • Nuxt Version: 3.11.2
  • CLI Version: 3.11.1
  • Nitro Version: 2.9.6
  • Package Manager: pnpm@8.5.1
  • Builder: -
  • User Config: devtools, extends, modules, runtimeConfig
  • Runtime Modules: @nuxt/image@1.5.0
  • Build Modules: -

Reproduction

Reproduction url: https://stackblitz.com/edit/github-um9rcm?file=composables%2FuseAppFetch.ts

Describe the bug

I tried to create my custom composable using the link https://nuxt.com/docs/examples/advanced/use-custom-fetch-composable, but I encountered errors related to typing.
In useAppFetch on line 15.

No overload matches this call. Overload 1 of 2, '(request: NitroFetchRequest | Ref<NitroFetchRequest> | (() => NitroFetchRequest), opts?: UseFetchOptions<ResT extends void ? unknown : ResT, ... 4 more ..., ResT extends void ? "get" : AvailableRouterMethod<...>> | undefined): AsyncData<...>', gave the following error. Argument of type 'UseFetchOptions<ResT, ResT, KeysOf<ResT>, null, string & {}, AvailableRouterMethod<string & {}>>' is not assignable to parameter of type 'UseFetchOptions<ResT extends void ? unknown : ResT, ResT extends void ? unknown : ResT, KeysOf<ResT extends void ? unknown : ResT>, null, NitroFetchRequest, ResT extends void ? "get" : AvailableRouterMethod<...>>'. Type 'ResT extends void ? unknown : ResT' is not assignable to type 'ResT'. 'ResT' could be instantiated with an arbitrary type which could be unrelated to 'ResT extends void ? unknown : ResT'. Overload 2 of 2, '(request: NitroFetchRequest | Ref<NitroFetchRequest> | (() => NitroFetchRequest), opts?: UseFetchOptions<ResT extends void ? unknown : ResT, ... 4 more ..., ResT extends void ? "get" : AvailableRouterMethod<...>> | undefined): AsyncData<...>', gave the following error. Argument of type 'UseFetchOptions<ResT, ResT, KeysOf<ResT>, null, string & {}, AvailableRouterMethod<string & {}>>' is not assignable to parameter of type 'UseFetchOptions<ResT extends void ? unknown : ResT, ResT extends void ? unknown : ResT, KeysOf<ResT extends void ? unknown : ResT>, ResT extends void ? unknown : ResT, NitroFetchRequest, ResT extends void ? "get" : AvailableRouterMethod<...>>'. Type 'ResT extends void ? unknown : ResT' is not assignable to type 'ResT'. 'ResT' could be instantiated with an arbitrary type which could be unrelated to 'ResT extends void ? unknown : ResT'.(2769)

Screenshot 2024-05-10 at 11 36 59

Also in app.vue line 5 type error related to 'transform'. But for some reason in stackblitz.com error in app.vue is not displayed. If you copy whole code to VScode it show error.

Type '(res: Todo[]) => string[]' is not assignable to type '_Transform<Todo[], Todo[]>'. Type 'string[]' is not assignable to type 'Todo[] | Promise<Todo[]>'.ts(2322)

Screenshot 2024-05-10 at 11 35 18

It returns transformed value as expected.

Thanks in advance for helping.

Additional context

No response

Logs

No response

Remove <ResT> from useFetch

export function useAppFetch<ResT>(
  request: NitroFetchRequest,
  options: UseFetchOptions<ResT> = {}
) {
  const defaults: typeof options = {
    $fetch: useNuxtApp().$api,
  };

  const params = defu(options, defaults);

  // return useFetch<ResT>(request, params);
  return useFetch(request, params);
}

More info: https://notes.atinux.com/nuxt-custom-fetch

Remove <ResT> from useFetch

export function useAppFetch<ResT>(
  request: NitroFetchRequest,
  options: UseFetchOptions<ResT> = {}
) {
  const defaults: typeof options = {
    $fetch: useNuxtApp().$api,
  };

  const params = defu(options, defaults);

  // return useFetch<ResT>(request, params);
  return useFetch(request, params);
}

More info: https://notes.atinux.com/nuxt-custom-fetch

Thanks for solution, it fixes type error with custom useFetch, but error with transform still remains.

With transform ResT is the input and DataT is the output, just type the parameter of transform's function and let it infer the output.

// normal useFetch
const { data: todos } = useFetch("/todos", {
  transform: (res: Todo[]) => {
    return res.map((todo) => todo.title)
  },
})

Like this:

// custom useFetch
export function useAppFetch<ResT, DataT>(
  request: NitroFetchRequest,
  options: UseFetchOptions<ResT, DataT> = {}
) {
  const defaults: typeof options = {
    $fetch: useNuxtApp().$api,
  };

  const params = defu(options, defaults);

  return useFetch(request, params);
}


const { data: todos } = useAppFetch("/todos", {
  transform: (res: Todo[]) => {
    return res.map((todo) => todo.title)
  },
})

Doing this is wrong:

const { data: todos } = useFetch<Todo[]>("/todos", {
  transform: (res) => {
    return res.map((todo) => todo.title)
  },
})

Because you are saying that the data returned from useFetch is a Todo[], but that's not true, it's a string[].

With transform ResT is the input and DataT is the output, just type the parameter of transform's function and let it infer the output.

// normal useFetch
const { data: todos } = useFetch("/todos", {
  transform: (res: Todo[]) => {
    return res.map((todo) => todo.title)
  },
})

Like this:

// custom useFetch
export function useAppFetch<ResT, DataT>(
  request: NitroFetchRequest,
  options: UseFetchOptions<ResT, DataT> = {}
) {
  const defaults: typeof options = {
    $fetch: useNuxtApp().$api,
  };

  const params = defu(options, defaults);

  return useFetch(request, params);
}


const { data: todos } = useAppFetch("/todos", {
  transform: (res: Todo[]) => {
    return res.map((todo) => todo.title)
  },
})

Doing this is wrong:

const { data: todos } = useFetch<Todo[]>("/todos", {
  transform: (res) => {
    return res.map((todo) => todo.title)
  },
})

Because you are saying that the data returned from useFetch is a Todo[], but that's not true, it's a string[].

Thank you so much for the explanation. It works.