Skip to content

Commit 6f08200

Browse files
gwansikkTkDodo
andauthoredJun 4, 2024··
refactor(*): improved type inference for useQueries with skipToken (#7484)
* refactor(react-query): improved type inference for useQueries * test(react-query): improved type inference for useQueries with skipToken * refactor(vue-query): improved type inference for useQueries with skipToken * refactor(svelte-query): improved type inference for useQueries with skipToken * refactor(angular-query): improved type inference for useQueries with skipToken * refactor(solid-query): improved type inference for useQueries with skipToken * refactor(*): update defaultQueryOptions type * refactor(solid-query): updated defaultQueryOptions type in useQueries * test(vue-query): fixed test for useQueries with skipToken * refactor(vue-query): ensured accurate error type inference for `useQueries` * test(vue-query): fixed test for useQueries with skipToken --------- Co-authored-by: Dominik Dorfmeister <office@dorfmeister.cc>
1 parent 96aa461 commit 6f08200

File tree

7 files changed

+95
-190
lines changed

7 files changed

+95
-190
lines changed
 

‎packages/angular-query-experimental/src/inject-queries.ts

+15-37
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import type {
1212
QueryKey,
1313
QueryObserverOptions,
1414
QueryObserverResult,
15-
SkipToken,
1615
ThrowOnError,
1716
} from '@tanstack/query-core'
1817

@@ -33,6 +32,9 @@ type QueryObserverOptionsForCreateQueries<
3332
// Avoid TS depth-limit error in case of large array literal
3433
type MAXIMUM_DEPTH = 20
3534

35+
// Widen the type of the symbol to enable type inference even if skipToken is not immutable.
36+
type SkipTokenForUseQueries = symbol
37+
3638
type GetOptions<T> =
3739
// Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
3840
T extends {
@@ -56,30 +58,18 @@ type GetOptions<T> =
5658
T extends {
5759
queryFn?:
5860
| QueryFunction<infer TQueryFnData, infer TQueryKey>
59-
| SkipToken
61+
| SkipTokenForUseQueries
6062
select: (data: any) => infer TData
6163
throwOnError?: ThrowOnError<any, infer TError, any, any>
6264
}
6365
? QueryObserverOptionsForCreateQueries<
6466
TQueryFnData,
65-
TError,
66-
TData,
67+
unknown extends TError ? DefaultError : TError,
68+
unknown extends TData ? TQueryFnData : TData,
6769
TQueryKey
6870
>
69-
: T extends {
70-
queryFn?:
71-
| QueryFunction<infer TQueryFnData, infer TQueryKey>
72-
| SkipToken
73-
throwOnError?: ThrowOnError<any, infer TError, any, any>
74-
}
75-
? QueryObserverOptionsForCreateQueries<
76-
TQueryFnData,
77-
TError,
78-
TQueryFnData,
79-
TQueryKey
80-
>
81-
: // Fallback
82-
QueryObserverOptionsForCreateQueries
71+
: // Fallback
72+
QueryObserverOptionsForCreateQueries
8373

8474
type GetResults<T> =
8575
// Part 1: responsible for mapping explicit type parameter to function result, if object
@@ -98,24 +88,18 @@ type GetResults<T> =
9888
? QueryObserverResult<TQueryFnData>
9989
: // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
10090
T extends {
101-
queryFn?: QueryFunction<unknown, any>
91+
queryFn?:
92+
| QueryFunction<infer TQueryFnData, any>
93+
| SkipTokenForUseQueries
10294
select: (data: any) => infer TData
10395
throwOnError?: ThrowOnError<any, infer TError, any, any>
10496
}
10597
? QueryObserverResult<
106-
TData,
98+
unknown extends TData ? TQueryFnData : TData,
10799
unknown extends TError ? DefaultError : TError
108100
>
109-
: T extends {
110-
queryFn?: QueryFunction<infer TQueryFnData, any>
111-
throwOnError?: ThrowOnError<any, infer TError, any, any>
112-
}
113-
? QueryObserverResult<
114-
TQueryFnData,
115-
unknown extends TError ? DefaultError : TError
116-
>
117-
: // Fallback
118-
QueryObserverResult
101+
: // Fallback
102+
QueryObserverResult
119103

120104
/**
121105
* QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
@@ -224,13 +208,7 @@ export function injectQueries<
224208
// Make sure the results are already in fetching state before subscribing or updating options
225209
defaultedOptions._optimisticResults = 'optimistic'
226210

227-
return defaultedOptions as QueryObserverOptions<
228-
unknown,
229-
Error,
230-
unknown,
231-
unknown,
232-
QueryKey
233-
>
211+
return defaultedOptions as QueryObserverOptions
234212
})
235213
})
236214

‎packages/react-query/src/__tests__/useQueries.test-d.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { skipToken } from '..'
33
import { useQueries } from '../useQueries'
44
import { queryOptions } from '../queryOptions'
55
import type { OmitKeyof } from '..'
6-
import type { UseQueryOptions } from '../types'
6+
import type { UseQueryOptions, UseQueryResult } from '../types'
77

88
describe('UseQueries config object overload', () => {
99
it('TData should always be defined when initialData is provided as an object', () => {
@@ -136,8 +136,9 @@ describe('UseQueries config object overload', () => {
136136
],
137137
})
138138

139-
const data = queryResults[0].data
139+
const firstResult = queryResults[0]
140140

141-
expectTypeOf(data).toEqualTypeOf<number | undefined>()
141+
expectTypeOf(firstResult).toEqualTypeOf<UseQueryResult<number, Error>>()
142+
expectTypeOf(firstResult.data).toEqualTypeOf<number | undefined>()
142143
})
143144
})

‎packages/react-query/src/useQueries.ts

+14-39
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import type {
3434
QueryFunction,
3535
QueryKey,
3636
QueryObserverOptions,
37-
SkipToken,
3837
ThrowOnError,
3938
} from '@tanstack/query-core'
4039

@@ -55,6 +54,9 @@ type UseQueryOptionsForUseQueries<
5554
// Avoid TS depth-limit error in case of large array literal
5655
type MAXIMUM_DEPTH = 20
5756

57+
// Widen the type of the symbol to enable type inference even if skipToken is not immutable.
58+
type SkipTokenForUseQueries = symbol
59+
5860
type GetUseQueryOptionsForUseQueries<T> =
5961
// Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
6062
T extends {
@@ -78,30 +80,18 @@ type GetUseQueryOptionsForUseQueries<T> =
7880
T extends {
7981
queryFn?:
8082
| QueryFunction<infer TQueryFnData, infer TQueryKey>
81-
| SkipToken
83+
| SkipTokenForUseQueries
8284
select?: (data: any) => infer TData
8385
throwOnError?: ThrowOnError<any, infer TError, any, any>
8486
}
8587
? UseQueryOptionsForUseQueries<
8688
TQueryFnData,
87-
TError,
88-
TData,
89+
unknown extends TError ? DefaultError : TError,
90+
unknown extends TData ? TQueryFnData : TData,
8991
TQueryKey
9092
>
91-
: T extends {
92-
queryFn?:
93-
| QueryFunction<infer TQueryFnData, infer TQueryKey>
94-
| SkipToken
95-
throwOnError?: ThrowOnError<any, infer TError, any, any>
96-
}
97-
? UseQueryOptionsForUseQueries<
98-
TQueryFnData,
99-
TError,
100-
TQueryFnData,
101-
TQueryKey
102-
>
103-
: // Fallback
104-
UseQueryOptionsForUseQueries
93+
: // Fallback
94+
UseQueryOptionsForUseQueries
10595

10696
// A defined initialData setting should return a DefinedUseQueryResult rather than UseQueryResult
10797
type GetDefinedOrUndefinedQueryResult<T, TData, TError = unknown> = T extends {
@@ -137,7 +127,9 @@ type GetUseQueryResult<T> =
137127
? GetDefinedOrUndefinedQueryResult<T, TQueryFnData>
138128
: // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
139129
T extends {
140-
queryFn?: QueryFunction<infer TQueryFnData, any> | SkipToken
130+
queryFn?:
131+
| QueryFunction<infer TQueryFnData, any>
132+
| SkipTokenForUseQueries
141133
select?: (data: any) => infer TData
142134
throwOnError?: ThrowOnError<any, infer TError, any, any>
143135
}
@@ -146,19 +138,8 @@ type GetUseQueryResult<T> =
146138
unknown extends TData ? TQueryFnData : TData,
147139
unknown extends TError ? DefaultError : TError
148140
>
149-
: T extends {
150-
queryFn?:
151-
| QueryFunction<infer TQueryFnData, any>
152-
| SkipToken
153-
throwOnError?: ThrowOnError<any, infer TError, any, any>
154-
}
155-
? GetDefinedOrUndefinedQueryResult<
156-
T,
157-
TQueryFnData,
158-
unknown extends TError ? DefaultError : TError
159-
>
160-
: // Fallback
161-
UseQueryResult
141+
: // Fallback
142+
UseQueryResult
162143

163144
/**
164145
* QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
@@ -260,13 +241,7 @@ export function useQueries<
260241
() =>
261242
queries.map((opts) => {
262243
const defaultedOptions = client.defaultQueryOptions(
263-
opts as QueryObserverOptions<
264-
unknown,
265-
Error,
266-
unknown,
267-
unknown,
268-
QueryKey
269-
>,
244+
opts as QueryObserverOptions,
270245
)
271246

272247
// Make sure the results are already in fetching state before subscribing or updating options

‎packages/solid-query/src/createQueries.ts

+22-34
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import type {
2323
QueriesPlaceholderDataFunction,
2424
QueryFunction,
2525
QueryKey,
26+
QueryObserverOptions,
2627
QueryObserverResult,
27-
SkipToken,
2828
ThrowOnError,
2929
} from '@tanstack/query-core'
3030

@@ -52,6 +52,9 @@ type CreateQueryOptionsForCreateQueries<
5252
// Avoid TS depth-limit error in case of large array literal
5353
type MAXIMUM_DEPTH = 20
5454

55+
// Widen the type of the symbol to enable type inference even if skipToken is not immutable.
56+
type SkipTokenForUseQueries = symbol
57+
5558
type GetOptions<T> =
5659
// Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
5760
T extends {
@@ -75,30 +78,18 @@ type GetOptions<T> =
7578
T extends {
7679
queryFn?:
7780
| QueryFunction<infer TQueryFnData, infer TQueryKey>
78-
| SkipToken
81+
| SkipTokenForUseQueries
7982
select?: (data: any) => infer TData
8083
throwOnError?: ThrowOnError<any, infer TError, any, any>
8184
}
8285
? CreateQueryOptionsForCreateQueries<
8386
TQueryFnData,
84-
TError,
85-
TData,
87+
unknown extends TError ? DefaultError : TError,
88+
unknown extends TData ? TQueryFnData : TData,
8689
TQueryKey
8790
>
88-
: T extends {
89-
queryFn?:
90-
| QueryFunction<infer TQueryFnData, infer TQueryKey>
91-
| SkipToken
92-
throwOnError?: ThrowOnError<any, infer TError, any, any>
93-
}
94-
? CreateQueryOptionsForCreateQueries<
95-
TQueryFnData,
96-
TError,
97-
TQueryFnData,
98-
TQueryKey
99-
>
100-
: // Fallback
101-
CreateQueryOptionsForCreateQueries
91+
: // Fallback
92+
CreateQueryOptionsForCreateQueries
10293

10394
type GetResults<T> =
10495
// Part 1: responsible for mapping explicit type parameter to function result, if object
@@ -117,24 +108,18 @@ type GetResults<T> =
117108
? CreateQueryResult<TQueryFnData>
118109
: // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
119110
T extends {
120-
queryFn?: QueryFunction<infer TQueryFnData, any>
111+
queryFn?:
112+
| QueryFunction<infer TQueryFnData, any>
113+
| SkipTokenForUseQueries
121114
select?: (data: any) => infer TData
122115
throwOnError?: ThrowOnError<any, infer TError, any, any>
123116
}
124117
? CreateQueryResult<
125118
unknown extends TData ? TQueryFnData : TData,
126119
unknown extends TError ? DefaultError : TError
127120
>
128-
: T extends {
129-
queryFn?: QueryFunction<infer TQueryFnData, any>
130-
throwOnError?: ThrowOnError<any, infer TError, any, any>
131-
}
132-
? CreateQueryResult<
133-
TQueryFnData,
134-
unknown extends TError ? DefaultError : TError
135-
>
136-
: // Fallback
137-
CreateQueryResult
121+
: // Fallback
122+
CreateQueryResult
138123

139124
/**
140125
* QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
@@ -228,13 +213,16 @@ export function createQueries<
228213
const client = createMemo(() => useQueryClient(queryClient?.()))
229214
const isRestoring = useIsRestoring()
230215

231-
const defaultedQueries: QueriesOptions<any> = createMemo(() =>
216+
const defaultedQueries = createMemo(() =>
232217
queriesOptions().queries.map((options) =>
233-
mergeProps(client().defaultQueryOptions(options), {
234-
get _optimisticResults() {
235-
return isRestoring() ? 'isRestoring' : 'optimistic'
218+
mergeProps(
219+
client().defaultQueryOptions(options as QueryObserverOptions),
220+
{
221+
get _optimisticResults() {
222+
return isRestoring() ? 'isRestoring' : 'optimistic'
223+
},
236224
},
237-
}),
225+
),
238226
),
239227
)
240228

‎packages/svelte-query/src/createQueries.ts

+15-39
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import type {
1515
QueryKey,
1616
QueryObserverOptions,
1717
QueryObserverResult,
18-
SkipToken,
1918
ThrowOnError,
2019
} from '@tanstack/query-core'
2120

@@ -36,6 +35,9 @@ type QueryObserverOptionsForCreateQueries<
3635
// Avoid TS depth-limit error in case of large array literal
3736
type MAXIMUM_DEPTH = 20
3837

38+
// Widen the type of the symbol to enable type inference even if skipToken is not immutable.
39+
type SkipTokenForUseQueries = symbol
40+
3941
type GetOptions<T> =
4042
// Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
4143
T extends {
@@ -59,30 +61,18 @@ type GetOptions<T> =
5961
T extends {
6062
queryFn?:
6163
| QueryFunction<infer TQueryFnData, infer TQueryKey>
62-
| SkipToken
64+
| SkipTokenForUseQueries
6365
select?: (data: any) => infer TData
6466
throwOnError?: ThrowOnError<any, infer TError, any, any>
6567
}
6668
? QueryObserverOptionsForCreateQueries<
6769
TQueryFnData,
68-
TError,
69-
TData,
70+
unknown extends TError ? DefaultError : TError,
71+
unknown extends TData ? TQueryFnData : TData,
7072
TQueryKey
7173
>
72-
: T extends {
73-
queryFn?:
74-
| QueryFunction<infer TQueryFnData, infer TQueryKey>
75-
| SkipToken
76-
throwOnError?: ThrowOnError<any, infer TError, any, any>
77-
}
78-
? QueryObserverOptionsForCreateQueries<
79-
TQueryFnData,
80-
TError,
81-
TQueryFnData,
82-
TQueryKey
83-
>
84-
: // Fallback
85-
QueryObserverOptionsForCreateQueries
74+
: // Fallback
75+
QueryObserverOptionsForCreateQueries
8676

8777
type GetResults<T> =
8878
// Part 1: responsible for mapping explicit type parameter to function result, if object
@@ -101,26 +91,18 @@ type GetResults<T> =
10191
? QueryObserverResult<TQueryFnData>
10292
: // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
10393
T extends {
104-
queryFn?: QueryFunction<infer TQueryFnData, any> | SkipToken
94+
queryFn?:
95+
| QueryFunction<infer TQueryFnData, any>
96+
| SkipTokenForUseQueries
10597
select?: (data: any) => infer TData
10698
throwOnError?: ThrowOnError<any, infer TError, any, any>
10799
}
108100
? QueryObserverResult<
109101
unknown extends TData ? TQueryFnData : TData,
110102
unknown extends TError ? DefaultError : TError
111103
>
112-
: T extends {
113-
queryFn?:
114-
| QueryFunction<infer TQueryFnData, any>
115-
| SkipToken
116-
throwOnError?: ThrowOnError<any, infer TError, any, any>
117-
}
118-
? QueryObserverResult<
119-
TQueryFnData,
120-
unknown extends TError ? DefaultError : TError
121-
>
122-
: // Fallback
123-
QueryObserverResult
104+
: // Fallback
105+
QueryObserverResult
124106

125107
/**
126108
* QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
@@ -141,7 +123,7 @@ export type QueriesOptions<
141123
[...TResult, GetOptions<Head>],
142124
[...TDepth, 1]
143125
>
144-
: Readonly<unknown> extends T
126+
: ReadonlyArray<unknown> extends T
145127
? T
146128
: // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!
147129
// use this to infer the param types in the case of Array.map() argument
@@ -224,13 +206,7 @@ export function createQueries<
224206
([$queries, $isRestoring]) => {
225207
return $queries.map((opts) => {
226208
const defaultedOptions = client.defaultQueryOptions(
227-
opts as QueryObserverOptions<
228-
unknown,
229-
Error,
230-
unknown,
231-
unknown,
232-
QueryKey
233-
>,
209+
opts as QueryObserverOptions,
234210
)
235211
// Make sure the results are already in fetching state before subscribing or updating options
236212
defaultedOptions._optimisticResults = $isRestoring

‎packages/vue-query/src/__tests__/useQueries.test-d.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { describe, expectTypeOf, it } from 'vitest'
22
import { reactive } from 'vue'
33
import { skipToken, useQueries } from '..'
44
import { queryOptions } from '../queryOptions'
5-
import type { OmitKeyof } from '..'
5+
import type { OmitKeyof, QueryObserverResult } from '..'
66
import type { UseQueryOptions } from '../useQuery'
77

88
describe('UseQueries config object overload', () => {
@@ -110,7 +110,12 @@ describe('UseQueries config object overload', () => {
110110
],
111111
})
112112

113-
expectTypeOf(queriesState[0].data).toEqualTypeOf<number | undefined>()
113+
const firstResult = queriesState[0]
114+
115+
expectTypeOf(firstResult).toEqualTypeOf<
116+
QueryObserverResult<number, Error>
117+
>()
118+
expectTypeOf(firstResult.data).toEqualTypeOf<number | undefined>()
114119
})
115120

116121
describe('custom hook', () => {

‎packages/vue-query/src/useQueries.ts

+18-36
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ type UseQueryOptionsForUseQueries<
4242
// Avoid TS depth-limit error in case of large array literal
4343
type MAXIMUM_DEPTH = 20
4444

45+
// Widen the type of the symbol to enable type inference even if skipToken is not immutable.
46+
type SkipTokenForUseQueries = symbol
47+
4548
type GetOptions<T> =
4649
// Part 1: if UseQueryOptions are already being sent through, then just return T
4750
T extends UseQueryOptions
@@ -66,34 +69,20 @@ type GetOptions<T> =
6669
? UseQueryOptionsForUseQueries<TQueryFnData>
6770
: // Part 4: responsible for inferring and enforcing type if no explicit parameter was provided
6871
T extends {
69-
queryFn?: QueryFunction<
70-
infer TQueryFnData,
71-
infer TQueryKey
72-
>
72+
queryFn?:
73+
| QueryFunction<infer TQueryFnData, infer TQueryKey>
74+
| SkipTokenForUseQueries
7375
select?: (data: any) => infer TData
7476
throwOnError?: ThrowOnError<any, infer TError, any, any>
7577
}
7678
? UseQueryOptionsForUseQueries<
7779
TQueryFnData,
78-
TError,
79-
TData,
80+
unknown extends TError ? DefaultError : TError,
81+
unknown extends TData ? TQueryFnData : TData,
8082
TQueryKey
8183
>
82-
: T extends {
83-
queryFn?: QueryFunction<
84-
infer TQueryFnData,
85-
infer TQueryKey
86-
>
87-
throwOnError?: ThrowOnError<any, infer TError, any, any>
88-
}
89-
? UseQueryOptionsForUseQueries<
90-
TQueryFnData,
91-
TError,
92-
TQueryFnData,
93-
TQueryKey
94-
>
95-
: // Fallback
96-
UseQueryOptionsForUseQueries
84+
: // Fallback
85+
UseQueryOptionsForUseQueries
9786

9887
// A defined initialData setting should return a DefinedQueryObserverResult rather than QueryObserverResult
9988
type GetDefinedOrUndefinedQueryResult<T, TData, TError = unknown> = T extends {
@@ -124,7 +113,7 @@ type GetResults<T> =
124113
? GetDefinedOrUndefinedQueryResult<
125114
T,
126115
undefined extends TData ? TQueryFnData : TData,
127-
TError
116+
unknown extends TError ? DefaultError : TError
128117
>
129118
: // Part 2: responsible for mapping explicit type parameter to function result, if object
130119
T extends { queryFnData: any; error?: infer TError; data: infer TData }
@@ -142,7 +131,9 @@ type GetResults<T> =
142131
? GetDefinedOrUndefinedQueryResult<T, TQueryFnData>
143132
: // Part 4: responsible for mapping inferred type to results, if no explicit parameter was provided
144133
T extends {
145-
queryFn?: QueryFunction<infer TQueryFnData, any>
134+
queryFn?:
135+
| QueryFunction<infer TQueryFnData, any>
136+
| SkipTokenForUseQueries
146137
select?: (data: any) => infer TData
147138
throwOnError?: ThrowOnError<any, infer TError, any, any>
148139
}
@@ -151,17 +142,8 @@ type GetResults<T> =
151142
unknown extends TData ? TQueryFnData : TData,
152143
unknown extends TError ? DefaultError : TError
153144
>
154-
: T extends {
155-
queryFn?: QueryFunction<infer TQueryFnData, any>
156-
throwOnError?: ThrowOnError<any, infer TError, any, any>
157-
}
158-
? GetDefinedOrUndefinedQueryResult<
159-
T,
160-
TQueryFnData,
161-
unknown extends TError ? DefaultError : TError
162-
>
163-
: // Fallback
164-
QueryObserverResult
145+
: // Fallback
146+
QueryObserverResult
165147

166148
/**
167149
* UseQueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
@@ -182,7 +164,7 @@ export type UseQueriesOptions<
182164
[...TResult, GetOptions<Head>],
183165
[...TDepth, 1]
184166
>
185-
: Readonly<unknown> extends T
167+
: ReadonlyArray<unknown> extends T
186168
? T
187169
: // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!
188170
// use this to infer the param types in the case of Array.map() argument
@@ -236,7 +218,7 @@ export type UseQueriesResults<
236218
Array<
237219
QueryObserverResult<
238220
unknown extends TData ? TQueryFnData : TData,
239-
TError
221+
unknown extends TError ? DefaultError : TError
240222
>
241223
>
242224
: // Fallback

0 commit comments

Comments
 (0)
Please sign in to comment.