Type error when using experimental_createPersister with a queryFn that has an argument
Describe the bug
When using experimental_createPersister from @tanstack/query-persist-client-core, TypeScript throws a type error in queryOptions() when queryFn has an argument, but doesn't throw a type error if queryFn has no arguments. The type error goes away if we define the generic argument on queryOptions().
Your minimal, reproducible example
https://codesandbox.io/p/github/EliasWatson/tanstack-query-persist-bug-example/main?import=true
Steps to reproduce
- Write a function to create a
QueryPersisterusingexperimental_createPersister.
function createPersister<TData>(): QueryPersister<TData, any> {
return experimental_createPersister({ storage: undefined });
}
- Create query options using the persister function with a
queryFnthat has no arguments. Notice that there are no TypeScript errors.
queryOptions({
queryKey: ['good-query'],
queryFn: () => 'test',
persister: createPersister<string>(),
});
- Add an argument to the
queryFn. Notice that TypeScript now throws an error.
queryOptions({
queryKey: ['bad-query'],
// Ignoring the unused variable error:
// @ts-expect-error
queryFn: (args) => 'test',
persister: createPersister<string>(), // Type error here!
});
src/App.tsx:23:5 - error TS2769: No overload matches this call.
Overload 1 of 2, '(options: DefinedInitialDataOptions<unknown, Error, unknown, string[]>): UseQueryOptions<unknown, Error, unknown, string[]> & { initialData: unknown; } & { ...; }', gave the following error.
Types of parameters 'queryFn' and 'queryFn' are incompatible.
Type 'unknown' is not assignable to type 'string | Promise<string>'.
Overload 2 of 2, '(options: UndefinedInitialDataOptions<unknown, Error, unknown, string[]>): UseQueryOptions<unknown, Error, unknown, string[]> & { initialData?: InitialDataFunction<...> | undefined; } & { ...; }', gave the following error.
Type '(queryFn: QueryFunction<string, any, never>, context: { queryKey: any; signal: AbortSignal; meta: Record<string, unknown> | undefined; pageParam?: unknown; direction?: unknown; }, query: Query<...>) => string | Promise<...>' is not assignable to type '(queryFn: QueryFunction<unknown, string[], never>, context: { queryKey: string[]; signal: AbortSignal; meta: Record<string, unknown> | undefined; pageParam?: unknown; direction?: unknown; }, query: Query<...>) => unknown'.
23 persister: createPersister<string>(),
~~~~~~~~~
node_modules/@tanstack/query-core/build/modern/hydration-DtrabBHC.d.ts:577:5
577 persister?: QueryPersister<NoInfer<TQueryFnData>, NoInfer<TQueryKey>, NoInfer<TPageParam>>;
~~~~~~~~~
The expected type comes from property 'persister' which is declared here on type 'DefinedInitialDataOptions<unknown, Error, unknown, string[]>'
node_modules/@tanstack/query-core/build/modern/hydration-DtrabBHC.d.ts:577:5
577 persister?: QueryPersister<NoInfer<TQueryFnData>, NoInfer<TQueryKey>, NoInfer<TPageParam>>;
~~~~~~~~~
The expected type comes from property 'persister' which is declared here on type 'UndefinedInitialDataOptions<unknown, Error, unknown, string[]>'
- Specify the generic argument on
queryOptions. Notice that the TypeScript error goes away.
queryOptions<string>({
queryKey: ['fixed-bad-query'],
// Ignoring the unused variable error:
// @ts-expect-error
queryFn: (args) => 'test',
persister: createPersister<string>(),
});
Expected behavior
I expect TypeScript to not throw a type error when queryFn has an argument, just like it does when queryFn doesn't have arguments. I also don't want to have to specify the generic type on queryOptions since TypeScript has no problem inferring it when queryFn has no arguments.
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
- OS: MacOS
- Browser: Google Chrome
- Version: 127.0.6533.89 (Official Build) (arm64)
Tanstack Query adapter
react-query
TanStack Query version
v5.51.18
TypeScript version
v5.2.2
Additional context
No response
it works if you omit the return type declaration QueryPersister<TData, any>:
I think it's related to "Intra expression inference" maybe ? TypeScript does inference differently if function parameters are used. Could be related to:
- https://github.com/microsoft/TypeScript/issues/53018
You can see that if you hover queryOptions where it errors, it's actually inferred as queryOptions<unknown, Error, unknown, string[]>. So data is of type unknown instead of string, which I think is because it can't be inferred from the queryFn for "reasons" 🤷