Skip to content

Commit

Permalink
fix(types): fix issues with queryOptions factory method types (#8394)
Browse files Browse the repository at this point in the history
* Fix issues with queryOptions factory method types

* Apply the same fixes to infiniteQueryOptions

* Revert change to failing test

* Fix test in more userland way

* Unused import

* Add tRPC-style solution

* Unused import

---------

Co-authored-by: Dominik Dorfmeister <office@dorfmeister.cc>
  • Loading branch information
Nick-Lucas and TkDodo authored Dec 17, 2024
1 parent 4521a04 commit 4989399
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 23 deletions.
9 changes: 2 additions & 7 deletions packages/query-core/src/__tests__/queryClient.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -228,16 +228,11 @@ describe('fully typed usage', () => {
TData,
TError,
TData,
QueryKey & DataTag<unknown, TData, TError>
DataTag<QueryKey, TData, TError>
> = {
predicate(query) {
expectTypeOf(query).toEqualTypeOf<
Query<
TData,
TError,
TData,
QueryKey & DataTag<unknown, TData, TError>
>
Query<TData, TError, TData, DataTag<QueryKey, TData, TError>>
>()
expectTypeOf(query.state.data).toEqualTypeOf<TData | undefined>()
expectTypeOf(query.state.error).toEqualTypeOf<TError | null>()
Expand Down
4 changes: 2 additions & 2 deletions packages/query-core/src/__tests__/utils.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('QueryFilters', () => {
TData,
Error,
TData,
QueryKey & DataTag<unknown, TData>
DataTag<QueryKey, TData>
> = {
predicate(query) {
expectTypeOf(query.setData({ a: 1, b: '1' })).toEqualTypeOf<TData>()
Expand All @@ -37,7 +37,7 @@ describe('QueryFilters', () => {
TData,
TError,
TData,
QueryKey & DataTag<unknown, TData, TError>
DataTag<QueryKey, TData, TError>
> = {
predicate(query) {
expectTypeOf(query.setData({ a: 1, b: '1' })).toEqualTypeOf<TData>()
Expand Down
16 changes: 13 additions & 3 deletions packages/query-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, TValue, TError = UnsetMarker> = 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -200,4 +204,38 @@ describe('infiniteQueryOptions', () => {
| undefined
>()
})

it('should return a custom query key type', () => {
type MyQueryKey = [Array<string>, { type: 'foo' }]

const options = infiniteQueryOptions({
queryKey: [['key'], { type: 'foo' }] as MyQueryKey,
queryFn: () => Promise.resolve(1),
getNextPageParam: () => 1,
initialPageParam: 1,
})

expectTypeOf(options.queryKey).toEqualTypeOf<
DataTag<MyQueryKey, InfiniteData<number>, Error>
>()
})

it('should return a custom query key type with datatag', () => {
type MyQueryKey = DataTag<
[Array<string>, { 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<MyQueryKey, InfiniteData<number>, Error & { myMessage: string }>
>()
})
})
37 changes: 35 additions & 2 deletions packages/react-query/src/__tests__/queryOptions.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -236,7 +237,9 @@ describe('queryOptions', () => {
})

it('should be passable to UseQueryOptions', () => {
function somethingWithQueryOptions(options: UseQueryOptions<number>) {
function somethingWithQueryOptions<TQueryOpts extends AnyUseQueryOptions>(
options: TQueryOpts,
) {
return options.queryKey
}

Expand All @@ -247,4 +250,34 @@ describe('queryOptions', () => {

somethingWithQueryOptions(options)
})

it('should return a custom query key type', () => {
type MyQueryKey = [Array<string>, { type: 'foo' }]

const options = queryOptions({
queryKey: [['key'], { type: 'foo' }] as MyQueryKey,
queryFn: () => Promise.resolve(1),
})

expectTypeOf(options.queryKey).toEqualTypeOf<
DataTag<MyQueryKey, number, Error>
>()
})

it('should return a custom query key type with datatag', () => {
type MyQueryKey = DataTag<
[Array<string>, { type: 'foo' }],
number,
Error & { myMessage: string }
>

const options = queryOptions({
queryKey: [['key'], { type: 'foo' }] as MyQueryKey,
queryFn: () => Promise.resolve(1),
})

expectTypeOf(options.queryKey).toEqualTypeOf<
DataTag<MyQueryKey, number, Error & { myMessage: string }>
>()
})
})
6 changes: 3 additions & 3 deletions packages/react-query/src/infiniteQueryOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export function infiniteQueryOptions<
TQueryKey,
TPageParam
> & {
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>>
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>, TError>
}

export function infiniteQueryOptions<
Expand All @@ -128,7 +128,7 @@ export function infiniteQueryOptions<
TQueryKey,
TPageParam
> & {
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>>
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>, TError>
}

export function infiniteQueryOptions<
Expand All @@ -152,7 +152,7 @@ export function infiniteQueryOptions<
TQueryKey,
TPageParam
> & {
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>>
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>, TError>
}

export function infiniteQueryOptions(options: unknown) {
Expand Down
10 changes: 5 additions & 5 deletions packages/react-query/src/queryOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ export function queryOptions<
TQueryKey extends QueryKey = QueryKey,
>(
options: DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>,
): DefinedInitialDataOptions<TQueryFnData, TError, TData> & {
queryKey: DataTag<QueryKey, TQueryFnData>
): DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey> & {
queryKey: DataTag<TQueryKey, TQueryFnData, TError>
}

export function queryOptions<
Expand All @@ -66,8 +66,8 @@ export function queryOptions<
TQueryKey extends QueryKey = QueryKey,
>(
options: UnusedSkipTokenOptions<TQueryFnData, TError, TData, TQueryKey>,
): UnusedSkipTokenOptions<TQueryFnData, TError, TData> & {
queryKey: DataTag<QueryKey, TQueryFnData>
): UnusedSkipTokenOptions<TQueryFnData, TError, TData, TQueryKey> & {
queryKey: DataTag<TQueryKey, TQueryFnData, TError>
}

export function queryOptions<
Expand All @@ -78,7 +78,7 @@ export function queryOptions<
>(
options: UndefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>,
): UndefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey> & {
queryKey: DataTag<TQueryKey, TQueryFnData>
queryKey: DataTag<TQueryKey, TQueryFnData, TError>
}

export function queryOptions(options: unknown) {
Expand Down
25 changes: 25 additions & 0 deletions packages/react-query/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -31,6 +38,7 @@ export interface UseBaseQueryOptions<
TQueryKey
> {}

export type AnyUseQueryOptions = UseQueryOptions<any, any, any, any>
export interface UseQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
Expand All @@ -41,6 +49,12 @@ export interface UseQueryOptions<
'suspense'
> {}

export type AnyUseSuspenseQueryOptions = UseSuspenseQueryOptions<
any,
any,
any,
any
>
export interface UseSuspenseQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
Expand All @@ -56,6 +70,14 @@ export interface UseSuspenseQueryOptions<
>
}

export type AnyUseInfiniteQueryOptions = UseInfiniteQueryOptions<
any,
any,
any,
any,
any,
any
>
export interface UseInfiniteQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
Expand All @@ -75,6 +97,8 @@ export interface UseInfiniteQueryOptions<
'suspense'
> {}

export type AnyUseSuspenseInfiniteQueryOptions =
UseSuspenseInfiniteQueryOptions<any, any, any, any, any, any>
export interface UseSuspenseInfiniteQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
Expand Down Expand Up @@ -147,6 +171,7 @@ export type UseSuspenseInfiniteQueryResult<
'isPlaceholderData' | 'promise'
>

export type AnyUseMutationOptions = UseMutationOptions<any, any, any, any>
export interface UseMutationOptions<
TData = unknown,
TError = DefaultError,
Expand Down

0 comments on commit 4989399

Please sign in to comment.