Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TData generic can be inferred or specified incorrectly, causing unexpected runtime errors. #8639

Open
braeden opened this issue Feb 12, 2025 · 2 comments · May be fixed by #8654
Open

TData generic can be inferred or specified incorrectly, causing unexpected runtime errors. #8639

braeden opened this issue Feb 12, 2025 · 2 comments · May be fixed by #8654
Labels

Comments

@braeden
Copy link

braeden commented Feb 12, 2025

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 options
  • TData defaults 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:

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 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.
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

@TkDodo
Copy link
Collaborator

TkDodo commented Feb 14, 2025

Using NoInfer on the UseQueryResult<NoInfer, TError>, will at least prevent usePost2 issue

If that fixes it, please open a PR with that fix, including the appropriate type tests.

We should be able to write a conditional type by using additional overloads

We don’t want more overloads. If you add angle brackets <> to useQuery, you are basically doing a type assertion. I don’t want to add more complexity for that, as it’s not a recommended thing to do, as documented here: https://tanstack.com/query/v5/docs/framework/react/typescript

@TkDodo TkDodo added the types label Feb 14, 2025
@braeden braeden linked a pull request Feb 16, 2025 that will close this issue
@braeden
Copy link
Author

braeden commented Feb 16, 2025

Started draft PR here #8654 -- just indexed on useQuery to get first thoughts/before digging into how to more generally apply NoInfer to query-core types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants