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](https://private-user-images.githubusercontent.com/159756578/329482956-f13be891-2199-47f5-bb81-4d79ba6b3e8b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTU2NTIxOTIsIm5iZiI6MTcxNTY1MTg5MiwicGF0aCI6Ii8xNTk3NTY1NzgvMzI5NDgyOTU2LWYxM2JlODkxLTIxOTktNDdmNS1iYjgxLTRkNzliYTZiM2U4Yi5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjQwNTE0JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI0MDUxNFQwMTU4MTJaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0zZWE1ZjZkMzcwZjI1YjMxZTEzN2M0YWU1ZmE1MTA2OTM4ZGI1N2ZjYWY0MDBhZTk0YWFmNGI5NTFkZDBlZWFkJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZhY3Rvcl9pZD0wJmtleV9pZD0wJnJlcG9faWQ9MCJ9.LDcWrU4IHyBkO-u-nmY-0HWK71bxVuU2gHID56bl-0Q)
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](https://private-user-images.githubusercontent.com/159756578/329482568-2d9e59cf-93d2-4dfa-bcf5-a8fe1501127c.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTU2NTIxOTIsIm5iZiI6MTcxNTY1MTg5MiwicGF0aCI6Ii8xNTk3NTY1NzgvMzI5NDgyNTY4LTJkOWU1OWNmLTkzZDItNGRmYS1iY2Y1LWE4ZmUxNTAxMTI3Yy5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjQwNTE0JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI0MDUxNFQwMTU4MTJaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1lY2I5OGExOGI2MTZmMmExMTVlMDlhMDQyMTg2MmRiMmQxNGQ4ZDIwYzAzMzMwYzE2ODFmZDBkNjA0MTI2YWJiJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZhY3Rvcl9pZD0wJmtleV9pZD0wJnJlcG9faWQ9MCJ9.qm1mOOjPTFSv5z519faH2QTmFZPoSkWs84yjSRGWleY)
It returns transformed value as expected.
Thanks in advance for helping.
Additional context
No response
Logs
No response
Start a new pull request in StackBlitz Codeflow.
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 useFetchexport 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.