Describe the bug
Related to #4770, revitalizing since NoInfer/overloads can at least partially help.
TQueryFnData is directly inferred from queryFn specified in the hook options optionsTDatadefaults to TQueryFnData, but can be specified via a generic or annotated return type- When
TData generic is populated (by inference, or explicitly) , nothing enforces that there's type compatibility until you put a select function, leading to uncaught runtime breaks.
Your minimal, reproducible example
https://codesandbox.io/p/devbox/vigilant-forest-7j45zd?file=%2Fsrc%2Findex.tsx%3A58%2C1
Steps to reproduce
See that usePosts and usePosts2 both have a data type claiming to be number, but are instead a Post at runtime.
Examples:
functionusePosts(){returnuseQuery<Post[],Error,number,string[]>({queryKey: ['posts'],queryFn: async(): Promise<Array<Post>>=>{constresponse=awaitfetch('https://jsonplaceholder.typicode.com/posts');returnawaitresponse.json();},});}functionusePosts2(): UseQueryResult<number,Error>{returnuseQuery({queryKey: ['posts'],queryFn: async(): Promise<Array<Post>>=>{constresponse=awaitfetch('https://jsonplaceholder.typicode.com/posts');returnawaitresponse.json();},});}Expected behavior
I expect to get a type-error, because I haven't specified a select function and TQueryFnData does not equal TData, therefore we have easy, uncaught runtime breaks.
Potential solutions:
- Using
NoInfer on the UseQueryResult<NoInfer<TData>, TError>, will at least prevent usePost2 issue - We should be able to write a conditional type by using additional overloads (untested/hypothetically) to narrow on the condition where we have a
select specified.
typeUseQueryOptionsWithSelect= ...
typeUseQueryOptionsWithoutSelect= ...
declarefunctionuseQuery<TQueryFnData=unknown,TError=DefaultError,TData=TQueryFnData,TQueryKeyextendsQueryKey=QueryKey>(options: UseQueryOptionsWithoutSelect<TQueryFnData,TError,TData,TQueryKey>,queryClient?: QueryClient): UseQueryResult<TQueryFnDataextendsTData ? NoInfer<TData> : never,TError>;declarefunctionuseQuery<TQueryFnData=unknown,TError=DefaultError,TData=TQueryFnData,TQueryKeyextendsQueryKey=QueryKey>(options: UseQueryOptionsWithSelect<TQueryFnData,TError,TData,TQueryKey>,queryClient?: QueryClient): UseQueryResult<NoInfer<TData>,TError>;
How often does this bug happen?
None
Screenshots or Videos
No response
Platform
N/A
Tanstack Query adapter
None
TanStack Query version
5.66.0
TypeScript version
5.7.2
Additional context
No response
Describe the bug
Related to #4770, revitalizing since
NoInfer/overloads can at least partially help.TQueryFnDatais directly inferred fromqueryFnspecified in the hook optionsoptionsTDatadefaults toTQueryFnData, but can be specified via a generic or annotated return typeTDatageneric is populated (by inference, or explicitly) , nothing enforces that there's type compatibility until you put aselectfunction, leading to uncaught runtime breaks.Your minimal, reproducible example
https://codesandbox.io/p/devbox/vigilant-forest-7j45zd?file=%2Fsrc%2Findex.tsx%3A58%2C1
Steps to reproduce
See that
usePostsandusePosts2both have adatatype claiming to benumber, but are instead aPostat runtime.Examples:
Expected behavior
I expect to get a type-error, because I haven't specified a
selectfunction andTQueryFnDatadoes not equalTData, therefore we have easy, uncaught runtime breaks.Potential solutions:
NoInferon theUseQueryResult<NoInfer<TData>, TError>, will at least preventusePost2issueselectspecified.How often does this bug happen?
None
Screenshots or Videos
No response
Platform
N/A
Tanstack Query adapter
None
TanStack Query version
5.66.0
TypeScript version
5.7.2
Additional context
No response