diff --git a/packages/query-core/src/__tests__/queryClient.test-d.tsx b/packages/query-core/src/__tests__/queryClient.test-d.tsx index 4f0d42fc84..ddde0903ad 100644 --- a/packages/query-core/src/__tests__/queryClient.test-d.tsx +++ b/packages/query-core/src/__tests__/queryClient.test-d.tsx @@ -228,16 +228,11 @@ describe('fully typed usage', () => { TData, TError, TData, - QueryKey & DataTag + DataTag > = { predicate(query) { expectTypeOf(query).toEqualTypeOf< - Query< - TData, - TError, - TData, - QueryKey & DataTag - > + Query> >() expectTypeOf(query.state.data).toEqualTypeOf() expectTypeOf(query.state.error).toEqualTypeOf() diff --git a/packages/query-core/src/__tests__/utils.test-d.tsx b/packages/query-core/src/__tests__/utils.test-d.tsx index 2c602ddc3b..91be29f3d4 100644 --- a/packages/query-core/src/__tests__/utils.test-d.tsx +++ b/packages/query-core/src/__tests__/utils.test-d.tsx @@ -11,7 +11,7 @@ describe('QueryFilters', () => { TData, Error, TData, - QueryKey & DataTag + DataTag > = { predicate(query) { expectTypeOf(query.setData({ a: 1, b: '1' })).toEqualTypeOf() @@ -37,7 +37,7 @@ describe('QueryFilters', () => { TData, TError, TData, - QueryKey & DataTag + DataTag > = { predicate(query) { expectTypeOf(query.setData({ a: 1, b: '1' })).toEqualTypeOf() diff --git a/packages/query-core/src/types.ts b/packages/query-core/src/types.ts index a21016bf2c..ea43533811 100644 --- a/packages/query-core/src/types.ts +++ b/packages/query-core/src/types.ts @@ -46,10 +46,20 @@ export declare const dataTagSymbol: unique symbol export declare const dataTagErrorSymbol: unique symbol export declare const unsetMarker: unique symbol export type UnsetMarker = typeof unsetMarker -export type DataTag = TType & { - [dataTagSymbol]: TValue - [dataTagErrorSymbol]: TError +export type AnyDataTag = { + [dataTagSymbol]: any + [dataTagErrorSymbol]: any } +export type DataTag< + TType, + TValue, + TError = UnsetMarker, +> = TType extends AnyDataTag + ? TType + : TType & { + [dataTagSymbol]: TValue + [dataTagErrorSymbol]: TError + } export type QueryFunction< T = unknown, diff --git a/packages/react-query/src/__tests__/infiniteQueryOptions.test-d.tsx b/packages/react-query/src/__tests__/infiniteQueryOptions.test-d.tsx index 363ea1b37c..c5d7efeee9 100644 --- a/packages/react-query/src/__tests__/infiniteQueryOptions.test-d.tsx +++ b/packages/react-query/src/__tests__/infiniteQueryOptions.test-d.tsx @@ -4,7 +4,11 @@ import { infiniteQueryOptions } from '../infiniteQueryOptions' import { useInfiniteQuery } from '../useInfiniteQuery' import { useSuspenseInfiniteQuery } from '../useSuspenseInfiniteQuery' import { useQuery } from '../useQuery' -import type { InfiniteData, InitialDataFunction } from '@tanstack/query-core' +import type { + DataTag, + InfiniteData, + InitialDataFunction, +} from '@tanstack/query-core' describe('infiniteQueryOptions', () => { it('should not allow excess properties', () => { @@ -200,4 +204,38 @@ describe('infiniteQueryOptions', () => { | undefined >() }) + + it('should return a custom query key type', () => { + type MyQueryKey = [Array, { type: 'foo' }] + + const options = infiniteQueryOptions({ + queryKey: [['key'], { type: 'foo' }] as MyQueryKey, + queryFn: () => Promise.resolve(1), + getNextPageParam: () => 1, + initialPageParam: 1, + }) + + expectTypeOf(options.queryKey).toEqualTypeOf< + DataTag, Error> + >() + }) + + it('should return a custom query key type with datatag', () => { + type MyQueryKey = DataTag< + [Array, { type: 'foo' }], + number, + Error & { myMessage: string } + > + + const options = infiniteQueryOptions({ + queryKey: [['key'], { type: 'foo' }] as MyQueryKey, + queryFn: () => Promise.resolve(1), + getNextPageParam: () => 1, + initialPageParam: 1, + }) + + expectTypeOf(options.queryKey).toEqualTypeOf< + DataTag, Error & { myMessage: string }> + >() + }) }) diff --git a/packages/react-query/src/__tests__/queryOptions.test-d.tsx b/packages/react-query/src/__tests__/queryOptions.test-d.tsx index 414a621623..eb34463856 100644 --- a/packages/react-query/src/__tests__/queryOptions.test-d.tsx +++ b/packages/react-query/src/__tests__/queryOptions.test-d.tsx @@ -9,8 +9,9 @@ import { queryOptions } from '../queryOptions' import { useQuery } from '../useQuery' import { useQueries } from '../useQueries' import { useSuspenseQuery } from '../useSuspenseQuery' -import type { UseQueryOptions } from '../types' +import type { AnyUseQueryOptions } from '../types' import type { + DataTag, InitialDataFunction, QueryObserverResult, } from '@tanstack/query-core' @@ -236,7 +237,9 @@ describe('queryOptions', () => { }) it('should be passable to UseQueryOptions', () => { - function somethingWithQueryOptions(options: UseQueryOptions) { + function somethingWithQueryOptions( + options: TQueryOpts, + ) { return options.queryKey } @@ -247,4 +250,34 @@ describe('queryOptions', () => { somethingWithQueryOptions(options) }) + + it('should return a custom query key type', () => { + type MyQueryKey = [Array, { type: 'foo' }] + + const options = queryOptions({ + queryKey: [['key'], { type: 'foo' }] as MyQueryKey, + queryFn: () => Promise.resolve(1), + }) + + expectTypeOf(options.queryKey).toEqualTypeOf< + DataTag + >() + }) + + it('should return a custom query key type with datatag', () => { + type MyQueryKey = DataTag< + [Array, { type: 'foo' }], + number, + Error & { myMessage: string } + > + + const options = queryOptions({ + queryKey: [['key'], { type: 'foo' }] as MyQueryKey, + queryFn: () => Promise.resolve(1), + }) + + expectTypeOf(options.queryKey).toEqualTypeOf< + DataTag + >() + }) }) diff --git a/packages/react-query/src/infiniteQueryOptions.ts b/packages/react-query/src/infiniteQueryOptions.ts index 594c4217e2..d834bd5987 100644 --- a/packages/react-query/src/infiniteQueryOptions.ts +++ b/packages/react-query/src/infiniteQueryOptions.ts @@ -104,7 +104,7 @@ export function infiniteQueryOptions< TQueryKey, TPageParam > & { - queryKey: DataTag> + queryKey: DataTag, TError> } export function infiniteQueryOptions< @@ -128,7 +128,7 @@ export function infiniteQueryOptions< TQueryKey, TPageParam > & { - queryKey: DataTag> + queryKey: DataTag, TError> } export function infiniteQueryOptions< @@ -152,7 +152,7 @@ export function infiniteQueryOptions< TQueryKey, TPageParam > & { - queryKey: DataTag> + queryKey: DataTag, TError> } export function infiniteQueryOptions(options: unknown) { diff --git a/packages/react-query/src/queryOptions.ts b/packages/react-query/src/queryOptions.ts index b137d9688d..714d38a5f7 100644 --- a/packages/react-query/src/queryOptions.ts +++ b/packages/react-query/src/queryOptions.ts @@ -55,8 +55,8 @@ export function queryOptions< TQueryKey extends QueryKey = QueryKey, >( options: DefinedInitialDataOptions, -): DefinedInitialDataOptions & { - queryKey: DataTag +): DefinedInitialDataOptions & { + queryKey: DataTag } export function queryOptions< @@ -66,8 +66,8 @@ export function queryOptions< TQueryKey extends QueryKey = QueryKey, >( options: UnusedSkipTokenOptions, -): UnusedSkipTokenOptions & { - queryKey: DataTag +): UnusedSkipTokenOptions & { + queryKey: DataTag } export function queryOptions< @@ -78,7 +78,7 @@ export function queryOptions< >( options: UndefinedInitialDataOptions, ): UndefinedInitialDataOptions & { - queryKey: DataTag + queryKey: DataTag } export function queryOptions(options: unknown) { diff --git a/packages/react-query/src/types.ts b/packages/react-query/src/types.ts index 8516536361..9f6d7c315f 100644 --- a/packages/react-query/src/types.ts +++ b/packages/react-query/src/types.ts @@ -17,6 +17,13 @@ import type { SkipToken, } from '@tanstack/query-core' +export type AnyUseBaseQueryOptions = UseBaseQueryOptions< + any, + any, + any, + any, + any +> export interface UseBaseQueryOptions< TQueryFnData = unknown, TError = DefaultError, @@ -31,6 +38,7 @@ export interface UseBaseQueryOptions< TQueryKey > {} +export type AnyUseQueryOptions = UseQueryOptions export interface UseQueryOptions< TQueryFnData = unknown, TError = DefaultError, @@ -41,6 +49,12 @@ export interface UseQueryOptions< 'suspense' > {} +export type AnyUseSuspenseQueryOptions = UseSuspenseQueryOptions< + any, + any, + any, + any +> export interface UseSuspenseQueryOptions< TQueryFnData = unknown, TError = DefaultError, @@ -56,6 +70,14 @@ export interface UseSuspenseQueryOptions< > } +export type AnyUseInfiniteQueryOptions = UseInfiniteQueryOptions< + any, + any, + any, + any, + any, + any +> export interface UseInfiniteQueryOptions< TQueryFnData = unknown, TError = DefaultError, @@ -75,6 +97,8 @@ export interface UseInfiniteQueryOptions< 'suspense' > {} +export type AnyUseSuspenseInfiniteQueryOptions = + UseSuspenseInfiniteQueryOptions export interface UseSuspenseInfiniteQueryOptions< TQueryFnData = unknown, TError = DefaultError, @@ -147,6 +171,7 @@ export type UseSuspenseInfiniteQueryResult< 'isPlaceholderData' | 'promise' > +export type AnyUseMutationOptions = UseMutationOptions export interface UseMutationOptions< TData = unknown, TError = DefaultError,