Skip to content

Commit 3ca1327

Browse files
liaoliao666TkDodo
andauthored
fix(types): useQueries can not infer type of TError (#6155)
* fix(types): useQueries can not infer type of TError * test(useQueries): infer TError from throwOnError * types(queries): support to infer TError for queries of all frameworks --------- Co-authored-by: Dominik Dorfmeister <[email protected]>
1 parent f83fe47 commit 3ca1327

File tree

6 files changed

+157
-31
lines changed

6 files changed

+157
-31
lines changed

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

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,10 @@ describe('useQueries', () => {
377377
const key2 = queryKey()
378378
const key3 = queryKey()
379379
const key4 = queryKey()
380+
const key5 = queryKey()
381+
382+
type BizError = { code: number }
383+
const throwOnError = (_error: BizError) => true
380384

381385
// @ts-expect-error (Page component is not rendered)
382386
// eslint-disable-next-line
@@ -391,6 +395,18 @@ describe('useQueries', () => {
391395
expectTypeOf<Array<QueryObserverResult<number, unknown>>>(result1)
392396
expectTypeOf<number | undefined>(result1[0]?.data)
393397

398+
// Array.map preserves TError
399+
const result1_err = useQueries({
400+
queries: Array(50).map((_, i) => ({
401+
queryKey: ['key', i] as const,
402+
queryFn: () => i + 10,
403+
throwOnError,
404+
})),
405+
})
406+
expectTypeOf<Array<QueryObserverResult<number, unknown>>>(result1_err)
407+
expectTypeOf<number | undefined>(result1_err[0]?.data)
408+
expectTypeOf<BizError | null | undefined>(result1_err[0]?.error)
409+
394410
// Array.map preserves TData
395411
const result2 = useQueries({
396412
queries: Array(50).map((_, i) => ({
@@ -401,6 +417,16 @@ describe('useQueries', () => {
401417
})
402418
expectTypeOf<Array<QueryObserverResult<string, unknown>>>(result2)
403419

420+
const result2_err = useQueries({
421+
queries: Array(50).map((_, i) => ({
422+
queryKey: ['key', i] as const,
423+
queryFn: () => i + 10,
424+
select: (data: number) => data.toString(),
425+
throwOnError,
426+
})),
427+
})
428+
expectTypeOf<Array<QueryObserverResult<string, BizError>>>(result2_err)
429+
404430
const result3 = useQueries({
405431
queries: [
406432
{
@@ -416,15 +442,23 @@ describe('useQueries', () => {
416442
queryFn: () => ['string[]'],
417443
select: () => 123,
418444
},
445+
{
446+
queryKey: key5,
447+
queryFn: () => 'string',
448+
throwOnError,
449+
},
419450
],
420451
})
421452
expectTypeOf<QueryObserverResult<number, unknown>>(result3[0])
422453
expectTypeOf<QueryObserverResult<string, unknown>>(result3[1])
423454
expectTypeOf<QueryObserverResult<number, unknown>>(result3[2])
424455
expectTypeOf<number | undefined>(result3[0].data)
425456
expectTypeOf<string | undefined>(result3[1].data)
457+
expectTypeOf<string | undefined>(result3[3].data)
426458
// select takes precedence over queryFn
427459
expectTypeOf<number | undefined>(result3[2].data)
460+
// infer TError from throwOnError
461+
expectTypeOf<BizError | null | undefined>(result3[3].error)
428462

429463
// initialData/placeholderData are enforced
430464
useQueries({
@@ -446,7 +480,7 @@ describe('useQueries', () => {
446480
],
447481
})
448482

449-
// select params are "indirectly" enforced
483+
// select and throwOnError params are "indirectly" enforced
450484
useQueries({
451485
queries: [
452486
// unfortunately TS will not suggest the type for you
@@ -469,6 +503,11 @@ describe('useQueries', () => {
469503
queryFn: () => 'string',
470504
select: (a: string) => parseInt(a),
471505
},
506+
{
507+
queryKey: key5,
508+
queryFn: () => 'string',
509+
throwOnError,
510+
},
472511
],
473512
})
474513

@@ -504,11 +543,18 @@ describe('useQueries', () => {
504543
queryFn: () => 'string',
505544
select: (a: string) => parseInt(a),
506545
},
546+
{
547+
queryKey: key5,
548+
queryFn: () => 'string',
549+
select: (a: string) => parseInt(a),
550+
throwOnError,
551+
},
507552
],
508553
})
509554
expectTypeOf<QueryObserverResult<string, unknown>>(result4[0])
510555
expectTypeOf<QueryObserverResult<string, unknown>>(result4[1])
511556
expectTypeOf<QueryObserverResult<number, unknown>>(result4[2])
557+
expectTypeOf<QueryObserverResult<number, BizError>>(result4[3])
512558

513559
// handles when queryFn returns a Promise
514560
const result5 = useQueries({
@@ -532,10 +578,16 @@ describe('useQueries', () => {
532578
queryKey: ['key1'],
533579
queryFn: () => 123,
534580
},
581+
{
582+
queryKey: key5,
583+
queryFn: () => 'string',
584+
throwOnError,
585+
},
535586
],
536587
} as const)
537588
expectTypeOf<QueryObserverResult<string, unknown>>(result6[0])
538589
expectTypeOf<QueryObserverResult<number, unknown>>(result6[1])
590+
expectTypeOf<QueryObserverResult<string, BizError>>(result6[2])
539591

540592
// field names should be enforced - array literal
541593
useQueries({

packages/react-query/src/useQueries.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import type {
2424
QueryClient,
2525
QueryFunction,
2626
QueryKey,
27+
ThrowOnError,
2728
} from '@tanstack/query-core'
2829

2930
// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
@@ -66,10 +67,19 @@ type GetOptions<T> =
6667
T extends {
6768
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
6869
select: (data: any) => infer TData
70+
throwOnError?: ThrowOnError<any, infer TError, any, any>
6971
}
70-
? UseQueryOptionsForUseQueries<TQueryFnData, Error, TData, TQueryKey>
71-
: T extends { queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey> }
72-
? UseQueryOptionsForUseQueries<TQueryFnData, Error, TQueryFnData, TQueryKey>
72+
? UseQueryOptionsForUseQueries<TQueryFnData, TError, TData, TQueryKey>
73+
: T extends {
74+
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
75+
throwOnError?: ThrowOnError<any, infer TError, any, any>
76+
}
77+
? UseQueryOptionsForUseQueries<
78+
TQueryFnData,
79+
TError,
80+
TQueryFnData,
81+
TQueryKey
82+
>
7383
: // Fallback
7484
UseQueryOptionsForUseQueries
7585

@@ -92,10 +102,17 @@ type GetResults<T> =
92102
T extends {
93103
queryFn?: QueryFunction<unknown, any>
94104
select: (data: any) => infer TData
105+
throwOnError?: ThrowOnError<any, infer TError, any, any>
95106
}
96-
? UseQueryResult<TData>
97-
: T extends { queryFn?: QueryFunction<infer TQueryFnData, any> }
98-
? UseQueryResult<TQueryFnData>
107+
? UseQueryResult<TData, unknown extends TError ? DefaultError : TError>
108+
: T extends {
109+
queryFn?: QueryFunction<infer TQueryFnData, any>
110+
throwOnError?: ThrowOnError<any, infer TError, any, any>
111+
}
112+
? UseQueryResult<
113+
TQueryFnData,
114+
unknown extends TError ? DefaultError : TError
115+
>
99116
: // Fallback
100117
UseQueryResult
101118

packages/react-query/src/useSuspenseQueries.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
DefaultError,
77
QueryClient,
88
QueryFunction,
9+
ThrowOnError,
910
} from '@tanstack/query-core'
1011

1112
// Avoid TS depth-limit error in case of large array literal
@@ -34,10 +35,14 @@ type GetSuspenseOptions<T> =
3435
T extends {
3536
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
3637
select: (data: any) => infer TData
38+
throwOnError?: ThrowOnError<any, infer TError, any, any>
3739
}
38-
? UseSuspenseQueryOptions<TQueryFnData, Error, TData, TQueryKey>
39-
: T extends { queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey> }
40-
? UseSuspenseQueryOptions<TQueryFnData, Error, TQueryFnData, TQueryKey>
40+
? UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>
41+
: T extends {
42+
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
43+
throwOnError?: ThrowOnError<any, infer TError, any, any>
44+
}
45+
? UseSuspenseQueryOptions<TQueryFnData, TError, TQueryFnData, TQueryKey>
4146
: // Fallback
4247
UseSuspenseQueryOptions
4348

@@ -60,10 +65,20 @@ type GetSuspenseResults<T> =
6065
T extends {
6166
queryFn?: QueryFunction<unknown, any>
6267
select: (data: any) => infer TData
68+
throwOnError?: ThrowOnError<any, infer TError, any, any>
6369
}
64-
? UseSuspenseQueryResult<TData>
65-
: T extends { queryFn?: QueryFunction<infer TQueryFnData, any> }
66-
? UseSuspenseQueryResult<TQueryFnData>
70+
? UseSuspenseQueryResult<
71+
TData,
72+
unknown extends TError ? DefaultError : TError
73+
>
74+
: T extends {
75+
queryFn?: QueryFunction<infer TQueryFnData, any>
76+
throwOnError?: ThrowOnError<any, infer TError, any, any>
77+
}
78+
? UseSuspenseQueryResult<
79+
TQueryFnData,
80+
unknown extends TError ? DefaultError : TError
81+
>
6782
: // Fallback
6883
UseSuspenseQueryResult
6984

packages/solid-query/src/createQueries.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type {
2323
QueryFunction,
2424
QueryKey,
2525
QueryObserverResult,
26+
ThrowOnError,
2627
} from '@tanstack/query-core'
2728

2829
// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
@@ -65,12 +66,16 @@ type GetOptions<T> =
6566
T extends {
6667
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
6768
select: (data: any) => infer TData
69+
throwOnError?: ThrowOnError<any, infer TError, any, any>
70+
}
71+
? CreateQueryOptionsForCreateQueries<TQueryFnData, TError, TData, TQueryKey>
72+
: T extends {
73+
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
74+
throwOnError?: ThrowOnError<any, infer TError, any, any>
6875
}
69-
? CreateQueryOptionsForCreateQueries<TQueryFnData, Error, TData, TQueryKey>
70-
: T extends { queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey> }
7176
? CreateQueryOptionsForCreateQueries<
7277
TQueryFnData,
73-
Error,
78+
TError,
7479
TQueryFnData,
7580
TQueryKey
7681
>
@@ -96,10 +101,17 @@ type GetResults<T> =
96101
T extends {
97102
queryFn?: QueryFunction<unknown, any>
98103
select: (data: any) => infer TData
104+
throwOnError?: ThrowOnError<any, infer TError, any, any>
99105
}
100-
? CreateQueryResult<TData>
101-
: T extends { queryFn?: QueryFunction<infer TQueryFnData, any> }
102-
? CreateQueryResult<TQueryFnData>
106+
? CreateQueryResult<TData, unknown extends TError ? DefaultError : TError>
107+
: T extends {
108+
queryFn?: QueryFunction<infer TQueryFnData, any>
109+
throwOnError?: ThrowOnError<any, infer TError, any, any>
110+
}
111+
? CreateQueryResult<
112+
TQueryFnData,
113+
unknown extends TError ? DefaultError : TError
114+
>
103115
: // Fallback
104116
CreateQueryResult
105117

packages/svelte-query/src/createQueries.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type {
1414
QueryKey,
1515
QueryObserverOptions,
1616
QueryObserverResult,
17+
ThrowOnError,
1718
} from '@tanstack/query-core'
1819

1920
// This defines the `CreateQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
@@ -56,17 +57,21 @@ type GetOptions<T> =
5657
T extends {
5758
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
5859
select: (data: any) => infer TData
60+
throwOnError?: ThrowOnError<any, infer TError, any, any>
5961
}
6062
? QueryObserverOptionsForCreateQueries<
6163
TQueryFnData,
62-
Error,
64+
TError,
6365
TData,
6466
TQueryKey
6567
>
66-
: T extends { queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey> }
68+
: T extends {
69+
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
70+
throwOnError?: ThrowOnError<any, infer TError, any, any>
71+
}
6772
? QueryObserverOptionsForCreateQueries<
6873
TQueryFnData,
69-
Error,
74+
TError,
7075
TQueryFnData,
7176
TQueryKey
7277
>
@@ -92,10 +97,17 @@ type GetResults<T> =
9297
T extends {
9398
queryFn?: QueryFunction<unknown, any>
9499
select: (data: any) => infer TData
100+
throwOnError?: ThrowOnError<any, infer TError, any, any>
95101
}
96-
? QueryObserverResult<TData>
97-
: T extends { queryFn?: QueryFunction<infer TQueryFnData, any> }
98-
? QueryObserverResult<TQueryFnData>
102+
? QueryObserverResult<TData, unknown extends TError ? DefaultError : TError>
103+
: T extends {
104+
queryFn?: QueryFunction<infer TQueryFnData, any>
105+
throwOnError?: ThrowOnError<any, infer TError, any, any>
106+
}
107+
? QueryObserverResult<
108+
TQueryFnData,
109+
unknown extends TError ? DefaultError : TError
110+
>
99111
: // Fallback
100112
QueryObserverResult
101113

packages/vue-query/src/useQueries.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ import { useQueryClient } from './useQueryClient'
1313
import { cloneDeepUnref } from './utils'
1414
import type { Ref } from 'vue-demi'
1515
import type {
16+
DefaultError,
1617
QueriesObserverOptions,
1718
QueriesPlaceholderDataFunction,
1819
QueryFunction,
1920
QueryKey,
2021
QueryObserverResult,
22+
ThrowOnError,
2123
} from '@tanstack/query-core'
2224
import type { UseQueryOptions } from './useQuery'
2325
import type { QueryClient } from './queryClient'
@@ -63,10 +65,19 @@ type GetOptions<T> =
6365
T extends {
6466
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
6567
select: (data: any) => infer TData
68+
throwOnError?: ThrowOnError<any, infer TError, any, any>
6669
}
67-
? UseQueryOptionsForUseQueries<TQueryFnData, Error, TData, TQueryKey>
68-
: T extends { queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey> }
69-
? UseQueryOptionsForUseQueries<TQueryFnData, Error, TQueryFnData, TQueryKey>
70+
? UseQueryOptionsForUseQueries<TQueryFnData, TError, TData, TQueryKey>
71+
: T extends {
72+
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
73+
throwOnError?: ThrowOnError<any, infer TError, any, any>
74+
}
75+
? UseQueryOptionsForUseQueries<
76+
TQueryFnData,
77+
TError,
78+
TQueryFnData,
79+
TQueryKey
80+
>
7081
: // Fallback
7182
UseQueryOptionsForUseQueries
7283

@@ -89,10 +100,17 @@ type GetResults<T> =
89100
T extends {
90101
queryFn?: QueryFunction<unknown, any>
91102
select: (data: any) => infer TData
103+
throwOnError?: ThrowOnError<any, infer TError, any, any>
92104
}
93-
? QueryObserverResult<TData>
94-
: T extends { queryFn?: QueryFunction<infer TQueryFnData, any> }
95-
? QueryObserverResult<TQueryFnData>
105+
? QueryObserverResult<TData, unknown extends TError ? DefaultError : TError>
106+
: T extends {
107+
queryFn?: QueryFunction<infer TQueryFnData, any>
108+
throwOnError?: ThrowOnError<any, infer TError, any, any>
109+
}
110+
? QueryObserverResult<
111+
TQueryFnData,
112+
unknown extends TError ? DefaultError : TError
113+
>
96114
: // Fallback
97115
QueryObserverResult
98116

0 commit comments

Comments
 (0)