TanStack / query

🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.
https://tanstack.com/query
MIT License
42.67k stars 2.92k forks source link

`UseQueryOptions` type declaration regression, does not work for `useSuspenseQuery` #8258

Closed jaens closed 2 weeks ago

jaens commented 2 weeks ago

Describe the bug

In previous versions, useSuspenseQuery can take a UseQueryOptions<> type as a parameter.

After an upgrade, this no longer works, and instead throws a type error.

Argument of type 'UseQueryOptions<TData, TError, TVariables, TQueryKey>' is not assignable to parameter of type 'UseSuspenseQueryOptions<TData, TError, TVariables, TQueryKey>'.
  Types of property 'queryFn' are incompatible.
    Type 'unique symbol | QueryFunction<TData, TQueryKey, never> | undefined' is not assignable to type 'QueryFunction<TData, TQueryKey, never> | undefined'.
      Type 'typeof skipToken' is not assignable to type 'QueryFunction<TData, TQueryKey, never>'.ts(2345)

How is one supposed to declare the types of functions that return the return value of queryOptions?

I looked into the current type declarations, and due to the heavy overloading now going on there, this actually seems impossible to do cleanly?

Your minimal, reproducible example

not sure how this is supposed to work, the issue template does not show how to import Tanstack Query into the TypeScript playground

Steps to reproduce

export function useStandardSuspenseQuery<
    TArgs extends unknown[],
    TData,
    TError,
    TVariables,
    TQueryKey extends QueryKey,
>(fn: (api: ApiClient, ...args: TArgs) => UseQueryOptions<TData, TError, TVariables, TQueryKey>, ...args: TArgs) {
    const apiClient = useApiClient();
    return useSuspenseQuery(fn(apiClient, ...args));
}

useStandardSuspenseQuery(c => queryOptions({
    queryKey: ["test"],
    queryFn: async () => {
        return "test";
    },
}))

Expected behavior

No type error.

How often does this bug happen?

None

Screenshots or Videos

No response

Platform

TypeScript compiler

Tanstack Query adapter

React

TanStack Query version

5.59.20

TypeScript version

5.6.3

Additional context

No response

jaens commented 2 weeks ago

Actually, I guess I found a workaround: Changing all UseQueryOptions<> to UseSuspenseQueryOptions<> seems to make it work.

...since useQuery can also take UseSuspenseQueryOptions<> -- is that guaranteed?

What is the common supertype for both suspense and non-suspense query options?

DogPawHat commented 2 weeks ago

Yeah, I think it was changed in this pr https://github.com/TanStack/query/pull/8082

Basically, suspense can't take a skipToken but regular query can so they now have different options. UseSuspenseQueryOptions is therefore narrower and can fit in useQuery just fine.

TkDodo commented 2 weeks ago

yeah so passing queryOptions to useSuspenseQuery still works, but it fails if the queryFn is a skipToken.

If you build abstractions, you have to re-do what we do in our types; you can indeed just return SuspenseQueryOptions and pass those to either useQuery or useSuspsenseQuery