From d798d1c831bc35f7b8219b6ad0c20409a3522c4c Mon Sep 17 00:00:00 2001 From: Raashish Aggarwal <94279692+raashish1601@users.noreply.github.com> Date: Sat, 30 May 2026 19:20:11 +0530 Subject: [PATCH] fix(react-query): enforce selectless useQuery TData consistency --- .../src/__tests__/useQuery.test-d.tsx | 24 +++++++++++ packages/react-query/src/useQuery.ts | 41 ++++++++++++++++--- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/packages/react-query/src/__tests__/useQuery.test-d.tsx b/packages/react-query/src/__tests__/useQuery.test-d.tsx index fa104f5f922..d9bd4c7dd81 100644 --- a/packages/react-query/src/__tests__/useQuery.test-d.tsx +++ b/packages/react-query/src/__tests__/useQuery.test-d.tsx @@ -6,6 +6,7 @@ import type { OmitKeyof, QueryFunction, UseQueryOptions } from '..' describe('useQuery', () => { const key = queryKey() + type Post = { title: string } // unspecified query function should default to unknown const noQueryFn = useQuery({ queryKey: key }) @@ -56,6 +57,29 @@ describe('useQuery', () => { // @ts-expect-error useQuery({ queryKey: key, queryFn: () => 'test' }) + // should error when specifying TData that does not match queryFn data and no select transform is used + // @ts-expect-error + useQuery({ + queryKey: ['posts'], + queryFn: () => + Promise.resolve([ + { + title: 'Post', + } as Post, + ]), + }) + + useQuery({ + queryKey: ['posts'], + queryFn: () => + Promise.resolve([ + { + title: 'Post', + } as Post, + ]), + select: (posts) => posts.length, + }) + // it should infer the result type from a generic query function function queryFn(): Promise { return Promise.resolve({} as T) diff --git a/packages/react-query/src/useQuery.ts b/packages/react-query/src/useQuery.ts index c0f2a6a8404..0940db26c97 100644 --- a/packages/react-query/src/useQuery.ts +++ b/packages/react-query/src/useQuery.ts @@ -12,23 +12,54 @@ import type { UndefinedInitialDataOptions, } from './queryOptions' -export function useQuery< +type UseQueryOptionsWithSelect< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, +> = UseQueryOptions & { + select: Exclude< + UseQueryOptions['select'], + undefined + > +} + +type UseQueryOptionsWithoutSelect< + TQueryFnData = unknown, + TError = DefaultError, + TData = TQueryFnData, + TQueryKey extends QueryKey = QueryKey, +> = Omit, 'select'> + +export function useQuery< + TQueryFnData = unknown, + TError = DefaultError, + TData extends TQueryFnData = TQueryFnData, + TQueryKey extends QueryKey = QueryKey, >( - options: DefinedInitialDataOptions, + options: DefinedInitialDataOptions & + UseQueryOptionsWithoutSelect, queryClient?: QueryClient, ): DefinedUseQueryResult, TError> export function useQuery< TQueryFnData = unknown, TError = DefaultError, - TData = TQueryFnData, + TData extends TQueryFnData = TQueryFnData, + TQueryKey extends QueryKey = QueryKey, +>( + options: UndefinedInitialDataOptions & + UseQueryOptionsWithoutSelect, + queryClient?: QueryClient, +): UseQueryResult, TError> + +export function useQuery< + TQueryFnData = unknown, + TError = DefaultError, + TData extends TQueryFnData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, >( - options: UndefinedInitialDataOptions, + options: UseQueryOptionsWithoutSelect, queryClient?: QueryClient, ): UseQueryResult, TError> @@ -38,7 +69,7 @@ export function useQuery< TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, >( - options: UseQueryOptions, + options: UseQueryOptionsWithSelect, queryClient?: QueryClient, ): UseQueryResult, TError>