-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Open
Description
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 type- When
TDatageneric 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 usePosts and usePosts2 both have a data type claiming to be number, but are instead a Post at runtime.
Examples:
function usePosts() {
return useQuery<Post[], Error, number, string[]>({
queryKey: ['posts'],
queryFn: async (): Promise<Array<Post>> => {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts'
);
return await response.json();
},
});
}
function usePosts2(): UseQueryResult<number, Error> {
return useQuery({
queryKey: ['posts'],
queryFn: async (): Promise<Array<Post>> => {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts'
);
return await response.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
NoInferon theUseQueryResult<NoInfer<TData>, TError>, will at least preventusePost2issue - We should be able to write a conditional type by using additional overloads (untested/hypothetically) to narrow on the condition where we have a
selectspecified.
type UseQueryOptionsWithSelect = ...
type UseQueryOptionsWithoutSelect = ...
declare function useQuery<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(options: UseQueryOptionsWithoutSelect<TQueryFnData, TError, TData, TQueryKey>, queryClient?: QueryClient): UseQueryResult<TQueryFnData extends TData ? NoInfer<TData> : never, TError>;
declare function useQuery<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = 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