From c18313e3dce808a60e4fd80e89fed2851c25c746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Curley?= Date: Fri, 8 May 2026 16:28:31 +0100 Subject: [PATCH 1/5] feat(react-query): update usePrefetchQuery to use new imperitive methods plus tests --- .changeset/warm-candies-like.md | 5 ++ .../__tests__/infiniteQueryOptions.test-d.tsx | 40 ++++++++++++++++ .../src/__tests__/queryOptions.test-d.tsx | 10 ++++ .../src/__tests__/useInfiniteQuery.test-d.tsx | 12 +++++ .../usePrefetchInfiniteQuery.test-d.tsx | 23 ++++++++- .../src/__tests__/usePrefetchQuery.test-d.tsx | 12 +++++ packages/react-query/src/types.ts | 48 ++++++++++++++++--- .../src/usePrefetchInfiniteQuery.tsx | 13 +++-- packages/react-query/src/usePrefetchQuery.tsx | 15 ++++-- 9 files changed, 163 insertions(+), 15 deletions(-) create mode 100644 .changeset/warm-candies-like.md diff --git a/.changeset/warm-candies-like.md b/.changeset/warm-candies-like.md new file mode 100644 index 00000000000..291288f9214 --- /dev/null +++ b/.changeset/warm-candies-like.md @@ -0,0 +1,5 @@ +--- +'@tanstack/react-query': minor +--- + +move usePrefetchQuery to use new methods diff --git a/packages/react-query/src/__tests__/infiniteQueryOptions.test-d.tsx b/packages/react-query/src/__tests__/infiniteQueryOptions.test-d.tsx index 4f72db57d4c..16d9bbb81d5 100644 --- a/packages/react-query/src/__tests__/infiniteQueryOptions.test-d.tsx +++ b/packages/react-query/src/__tests__/infiniteQueryOptions.test-d.tsx @@ -51,6 +51,20 @@ describe('infiniteQueryOptions', () => { InfiniteData | undefined >() }) + it('should work when passed to useInfiniteQuery with select', () => { + const options = infiniteQueryOptions({ + queryKey: ['key'], + queryFn: () => Promise.resolve('string'), + getNextPageParam: () => 1, + initialPageParam: 1, + select: (data) => data.pages, + }) + + const { data } = useInfiniteQuery(options) + + // known issue: type of pageParams is unknown when returned from useInfiniteQuery + expectTypeOf(data).toEqualTypeOf | undefined>() + }) it('should work when passed to useSuspenseInfiniteQuery', () => { const options = infiniteQueryOptions({ queryKey: queryKey(), @@ -63,6 +77,19 @@ describe('infiniteQueryOptions', () => { expectTypeOf(data).toEqualTypeOf>() }) + it('should work when passed to useSuspenseInfiniteQuery with select', () => { + const options = infiniteQueryOptions({ + queryKey: ['key'], + queryFn: () => Promise.resolve('string'), + getNextPageParam: () => 1, + initialPageParam: 1, + select: (data) => data.pages, + }) + + const { data } = useSuspenseInfiniteQuery(options) + + expectTypeOf(data).toEqualTypeOf>() + }) it('should work when passed to infiniteQuery', async () => { const options = infiniteQueryOptions({ queryKey: ['key'], @@ -125,6 +152,19 @@ describe('infiniteQueryOptions', () => { expectTypeOf(data).toEqualTypeOf>() }) + it('should ignore select when passed to fetchInfiniteQuery', async () => { + const options = infiniteQueryOptions({ + queryKey: ['key'], + queryFn: () => Promise.resolve('string'), + getNextPageParam: () => 1, + initialPageParam: 1, + select: (data) => data.pages, + }) + + const data = await new QueryClient().fetchInfiniteQuery(options) + + expectTypeOf(data).toEqualTypeOf>() + }) it('should tag the queryKey with the result type of the QueryFn', () => { const { queryKey: tagged } = infiniteQueryOptions({ queryKey: queryKey(), diff --git a/packages/react-query/src/__tests__/queryOptions.test-d.tsx b/packages/react-query/src/__tests__/queryOptions.test-d.tsx index dfeedcff64b..36427c16ab4 100644 --- a/packages/react-query/src/__tests__/queryOptions.test-d.tsx +++ b/packages/react-query/src/__tests__/queryOptions.test-d.tsx @@ -105,6 +105,16 @@ describe('queryOptions', () => { const data = await new QueryClient().query(options) expectTypeOf(data).toEqualTypeOf() }) + it('should ignore select when passed to fetchQuery', async () => { + const options = queryOptions({ + queryKey: ['key'], + queryFn: () => Promise.resolve(5), + select: (data) => data.toString(), + }) + + const data = await new QueryClient().fetchQuery(options) + expectTypeOf(data).toEqualTypeOf() + }) it('should work when passed to useQueries', () => { const options = queryOptions({ queryKey: queryKey(), diff --git a/packages/react-query/src/__tests__/useInfiniteQuery.test-d.tsx b/packages/react-query/src/__tests__/useInfiniteQuery.test-d.tsx index ae272d85230..977cc53d76e 100644 --- a/packages/react-query/src/__tests__/useInfiniteQuery.test-d.tsx +++ b/packages/react-query/src/__tests__/useInfiniteQuery.test-d.tsx @@ -39,6 +39,18 @@ describe('pageParam', () => { }) }) + it('initialPageParam should define type of param passed to queryFunctionContext for infiniteQuery', () => { + const queryClient = new QueryClient() + queryClient.infiniteQuery({ + queryKey: ['key'], + queryFn: ({ pageParam }) => { + expectTypeOf(pageParam).toEqualTypeOf() + return Promise.resolve(pageParam) + }, + initialPageParam: 1, + }) + }) + it('initialPageParam should define type of param passed to queryFunctionContext for prefetchInfiniteQuery', () => { const queryClient = new QueryClient() queryClient.prefetchInfiniteQuery({ diff --git a/packages/react-query/src/__tests__/usePrefetchInfiniteQuery.test-d.tsx b/packages/react-query/src/__tests__/usePrefetchInfiniteQuery.test-d.tsx index 231c47cedb3..ace4904a3e0 100644 --- a/packages/react-query/src/__tests__/usePrefetchInfiniteQuery.test-d.tsx +++ b/packages/react-query/src/__tests__/usePrefetchInfiniteQuery.test-d.tsx @@ -1,6 +1,6 @@ import { assertType, describe, expectTypeOf, it } from 'vitest' import { queryKey } from '@tanstack/query-test-utils' -import { usePrefetchInfiniteQuery } from '..' +import { skipToken, usePrefetchInfiniteQuery } from '..' describe('usePrefetchInfiniteQuery', () => { it('should return nothing', () => { @@ -58,4 +58,25 @@ describe('usePrefetchInfiniteQuery', () => { }), ) }) + + it('should not allow skipToken in queryFn', () => { + assertType( + usePrefetchInfiniteQuery({ + queryKey: queryKey(), + // @ts-expect-error + queryFn: skipToken, + initialPageParam: 1, + getNextPageParam: () => 1, + }), + ) + assertType( + usePrefetchInfiniteQuery({ + queryKey: queryKey(), + // @ts-expect-error + queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5), + initialPageParam: 1, + getNextPageParam: () => 1, + }), + ) + }) }) diff --git a/packages/react-query/src/__tests__/usePrefetchQuery.test-d.tsx b/packages/react-query/src/__tests__/usePrefetchQuery.test-d.tsx index d5c1d7c2359..08e878d1d4e 100644 --- a/packages/react-query/src/__tests__/usePrefetchQuery.test-d.tsx +++ b/packages/react-query/src/__tests__/usePrefetchQuery.test-d.tsx @@ -57,4 +57,16 @@ describe('usePrefetchQuery', () => { }), ) }) + + it('should type queryFn and select data independently', () => { + usePrefetchQuery({ + queryKey: queryKey(), + queryFn: () => Promise.resolve('data'), + select: (data) => { + expectTypeOf(data).toEqualTypeOf<{ value: string }>() + + return data.value.length + }, + }) + }) }) diff --git a/packages/react-query/src/types.ts b/packages/react-query/src/types.ts index e4c446e50e8..7b794c2a77b 100644 --- a/packages/react-query/src/types.ts +++ b/packages/react-query/src/types.ts @@ -5,8 +5,8 @@ import type { DefinedInfiniteQueryObserverResult, DefinedQueryObserverResult, DistributiveOmit, - FetchQueryOptions, InfiniteData, + InfiniteQueryExecuteOptions, InfiniteQueryObserverOptions, InfiniteQueryObserverResult, MutateFunction, @@ -14,6 +14,7 @@ import type { MutationObserverResult, OmitKeyof, Override, + QueryExecuteOptions, QueryKey, QueryObserverOptions, QueryObserverResult, @@ -47,17 +48,52 @@ export interface UseBaseQueryOptions< subscribed?: boolean } -export interface UsePrefetchQueryOptions< +export type UsePrefetchQueryOptions< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, + TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, -> extends OmitKeyof< - FetchQueryOptions, +> = DistributiveOmit< + QueryExecuteOptions, 'queryFn' -> { +> & { + queryFn?: Exclude< + QueryExecuteOptions< + TQueryFnData, + TError, + TData, + TQueryData, + TQueryKey + >['queryFn'], + SkipToken + > +} + +export type UsePrefetchInfiniteQueryOptions< + TQueryFnData = unknown, + TError = DefaultError, + TData = InfiniteData, + TQueryKey extends QueryKey = QueryKey, + TPageParam = unknown, +> = DistributiveOmit< + InfiniteQueryExecuteOptions< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >, + 'queryFn' +> & { queryFn?: Exclude< - FetchQueryOptions['queryFn'], + InfiniteQueryExecuteOptions< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >['queryFn'], SkipToken > } diff --git a/packages/react-query/src/usePrefetchInfiniteQuery.tsx b/packages/react-query/src/usePrefetchInfiniteQuery.tsx index 08c2fcdfa3e..ab01ab55c07 100644 --- a/packages/react-query/src/usePrefetchInfiniteQuery.tsx +++ b/packages/react-query/src/usePrefetchInfiniteQuery.tsx @@ -1,19 +1,22 @@ +import { noop } from '@tanstack/query-core' import { useQueryClient } from './QueryClientProvider' + import type { DefaultError, - FetchInfiniteQueryOptions, + InfiniteData, QueryClient, QueryKey, } from '@tanstack/query-core' +import type { UsePrefetchInfiniteQueryOptions } from './types' export function usePrefetchInfiniteQuery< TQueryFnData = unknown, TError = DefaultError, - TData = TQueryFnData, + TData = InfiniteData, TQueryKey extends QueryKey = QueryKey, TPageParam = unknown, >( - options: FetchInfiniteQueryOptions< + options: UsePrefetchInfiniteQueryOptions< TQueryFnData, TError, TData, @@ -21,10 +24,10 @@ export function usePrefetchInfiniteQuery< TPageParam >, queryClient?: QueryClient, -) { +): void { const client = useQueryClient(queryClient) if (!client.getQueryState(options.queryKey)) { - client.prefetchInfiniteQuery(options) + void client.infiniteQuery(options).then(noop).catch(noop) } } diff --git a/packages/react-query/src/usePrefetchQuery.tsx b/packages/react-query/src/usePrefetchQuery.tsx index 3f508c33243..96989ea18ac 100644 --- a/packages/react-query/src/usePrefetchQuery.tsx +++ b/packages/react-query/src/usePrefetchQuery.tsx @@ -1,4 +1,6 @@ +import { noop } from '@tanstack/query-core' import { useQueryClient } from './QueryClientProvider' + import type { DefaultError, QueryClient, QueryKey } from '@tanstack/query-core' import type { UsePrefetchQueryOptions } from './types' @@ -6,14 +8,21 @@ export function usePrefetchQuery< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, + TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, >( - options: UsePrefetchQueryOptions, + options: UsePrefetchQueryOptions< + TQueryFnData, + TError, + TData, + TQueryData, + TQueryKey + >, queryClient?: QueryClient, -) { +): void { const client = useQueryClient(queryClient) if (!client.getQueryState(options.queryKey)) { - client.prefetchQuery(options) + void client.query(options).then(noop).catch(noop) } } From 44f46ca6db4970482925e57884c822f26df0d03e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Curley?= Date: Fri, 8 May 2026 18:36:43 +0100 Subject: [PATCH 2/5] docs(react-query): new docs for usePrefetchQuery --- docs/framework/react/reference/usePrefetchInfiniteQuery.md | 2 +- docs/framework/react/reference/usePrefetchQuery.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/framework/react/reference/usePrefetchInfiniteQuery.md b/docs/framework/react/reference/usePrefetchInfiniteQuery.md index 1e86a35b55d..497eb950d46 100644 --- a/docs/framework/react/reference/usePrefetchInfiniteQuery.md +++ b/docs/framework/react/reference/usePrefetchInfiniteQuery.md @@ -9,7 +9,7 @@ usePrefetchInfiniteQuery(options) **Options** -You can pass everything to `usePrefetchInfiniteQuery` that you can pass to [`queryClient.prefetchInfiniteQuery`](../../../reference/QueryClient.md#queryclientprefetchinfinitequery). Remember that some of them are required as below: +You can pass everything to `usePrefetchInfiniteQuery` that you can pass to [`queryClient.infiniteQuery`](../../../reference/QueryClient.md#queryclient-infinitequery). Remember that some of them are required as below: - `queryKey: QueryKey` - **Required** diff --git a/docs/framework/react/reference/usePrefetchQuery.md b/docs/framework/react/reference/usePrefetchQuery.md index 7feccad5fc7..593afd350f8 100644 --- a/docs/framework/react/reference/usePrefetchQuery.md +++ b/docs/framework/react/reference/usePrefetchQuery.md @@ -9,13 +9,13 @@ usePrefetchQuery(options) **Options** -You can pass everything to `usePrefetchQuery` that you can pass to [`queryClient.prefetchQuery`](../../../reference/QueryClient.md#queryclientprefetchquery). Remember that some of them are required as below: +You can pass everything to `usePrefetchQuery` that you can pass to [`queryClient.query`](../../../reference/QueryClient.md#queryclient-query). Remember that some of them are required as below: - `queryKey: QueryKey` - **Required** - The query key to prefetch during render -- `queryFn: (context: QueryFunctionContext) => Promise` +- `queryFn: (context: QueryFunctionContext) => TQueryFnData | Promise` - **Required, but only if no default query function has been defined** See [Default Query Function](../guides/default-query-function.md) for more information. **Returns** From 2fbf333d7d0ca03f045432219a91dfffacf27ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Curley?= Date: Mon, 17 Aug 2026 21:49:00 +0100 Subject: [PATCH 3/5] Update .changeset/warm-candies-like.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .changeset/warm-candies-like.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/warm-candies-like.md b/.changeset/warm-candies-like.md index 291288f9214..66b15027ea0 100644 --- a/.changeset/warm-candies-like.md +++ b/.changeset/warm-candies-like.md @@ -2,4 +2,4 @@ '@tanstack/react-query': minor --- -move usePrefetchQuery to use new methods +react-query: update usePrefetchQuery and usePrefetchInfiniteQuery to use queryClient.query and queryClient.infiniteQuery From 56e72f9d547d4dbf547c77b60f9fca7ad50f920d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Curley?= Date: Thu, 20 Aug 2026 11:29:48 +0100 Subject: [PATCH 4/5] Update packages/react-query/src/usePrefetchInfiniteQuery.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dominik Dorfmeister 🔮 --- packages/react-query/src/usePrefetchInfiniteQuery.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-query/src/usePrefetchInfiniteQuery.tsx b/packages/react-query/src/usePrefetchInfiniteQuery.tsx index ab01ab55c07..1cd5a3dff2e 100644 --- a/packages/react-query/src/usePrefetchInfiniteQuery.tsx +++ b/packages/react-query/src/usePrefetchInfiniteQuery.tsx @@ -28,6 +28,6 @@ export function usePrefetchInfiniteQuery< const client = useQueryClient(queryClient) if (!client.getQueryState(options.queryKey)) { - void client.infiniteQuery(options).then(noop).catch(noop) + void client.infiniteQuery(options).catch(noop) } } From 82ca35b4621831406a81263cc4c44cc539d55c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Curley?= Date: Thu, 20 Aug 2026 11:29:57 +0100 Subject: [PATCH 5/5] Update packages/react-query/src/usePrefetchQuery.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dominik Dorfmeister 🔮 --- packages/react-query/src/usePrefetchQuery.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-query/src/usePrefetchQuery.tsx b/packages/react-query/src/usePrefetchQuery.tsx index 96989ea18ac..1b0d5268cac 100644 --- a/packages/react-query/src/usePrefetchQuery.tsx +++ b/packages/react-query/src/usePrefetchQuery.tsx @@ -23,6 +23,6 @@ export function usePrefetchQuery< const client = useQueryClient(queryClient) if (!client.getQueryState(options.queryKey)) { - void client.query(options).then(noop).catch(noop) + void client.query(options).catch(noop) } }