Skip to content

Commit

Permalink
fix(types): useQueries can not infer type of TError (#6155)
Browse files Browse the repository at this point in the history
* 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 <office@dorfmeister.cc>
  • Loading branch information
liaoliao666 and TkDodo authored Oct 16, 2023
1 parent f83fe47 commit 3ca1327
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 31 deletions.
54 changes: 53 additions & 1 deletion packages/react-query/src/__tests__/useQueries.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,10 @@ describe('useQueries', () => {
const key2 = queryKey()
const key3 = queryKey()
const key4 = queryKey()
const key5 = queryKey()

type BizError = { code: number }
const throwOnError = (_error: BizError) => true

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

// Array.map preserves TError
const result1_err = useQueries({
queries: Array(50).map((_, i) => ({
queryKey: ['key', i] as const,
queryFn: () => i + 10,
throwOnError,
})),
})
expectTypeOf<Array<QueryObserverResult<number, unknown>>>(result1_err)
expectTypeOf<number | undefined>(result1_err[0]?.data)
expectTypeOf<BizError | null | undefined>(result1_err[0]?.error)

// Array.map preserves TData
const result2 = useQueries({
queries: Array(50).map((_, i) => ({
Expand All @@ -401,6 +417,16 @@ describe('useQueries', () => {
})
expectTypeOf<Array<QueryObserverResult<string, unknown>>>(result2)

const result2_err = useQueries({
queries: Array(50).map((_, i) => ({
queryKey: ['key', i] as const,
queryFn: () => i + 10,
select: (data: number) => data.toString(),
throwOnError,
})),
})
expectTypeOf<Array<QueryObserverResult<string, BizError>>>(result2_err)

const result3 = useQueries({
queries: [
{
Expand All @@ -416,15 +442,23 @@ describe('useQueries', () => {
queryFn: () => ['string[]'],
select: () => 123,
},
{
queryKey: key5,
queryFn: () => 'string',
throwOnError,
},
],
})
expectTypeOf<QueryObserverResult<number, unknown>>(result3[0])
expectTypeOf<QueryObserverResult<string, unknown>>(result3[1])
expectTypeOf<QueryObserverResult<number, unknown>>(result3[2])
expectTypeOf<number | undefined>(result3[0].data)
expectTypeOf<string | undefined>(result3[1].data)
expectTypeOf<string | undefined>(result3[3].data)
// select takes precedence over queryFn
expectTypeOf<number | undefined>(result3[2].data)
// infer TError from throwOnError
expectTypeOf<BizError | null | undefined>(result3[3].error)

// initialData/placeholderData are enforced
useQueries({
Expand All @@ -446,7 +480,7 @@ describe('useQueries', () => {
],
})

// select params are "indirectly" enforced
// select and throwOnError params are "indirectly" enforced
useQueries({
queries: [
// unfortunately TS will not suggest the type for you
Expand All @@ -469,6 +503,11 @@ describe('useQueries', () => {
queryFn: () => 'string',
select: (a: string) => parseInt(a),
},
{
queryKey: key5,
queryFn: () => 'string',
throwOnError,
},
],
})

Expand Down Expand Up @@ -504,11 +543,18 @@ describe('useQueries', () => {
queryFn: () => 'string',
select: (a: string) => parseInt(a),
},
{
queryKey: key5,
queryFn: () => 'string',
select: (a: string) => parseInt(a),
throwOnError,
},
],
})
expectTypeOf<QueryObserverResult<string, unknown>>(result4[0])
expectTypeOf<QueryObserverResult<string, unknown>>(result4[1])
expectTypeOf<QueryObserverResult<number, unknown>>(result4[2])
expectTypeOf<QueryObserverResult<number, BizError>>(result4[3])

// handles when queryFn returns a Promise
const result5 = useQueries({
Expand All @@ -532,10 +578,16 @@ describe('useQueries', () => {
queryKey: ['key1'],
queryFn: () => 123,
},
{
queryKey: key5,
queryFn: () => 'string',
throwOnError,
},
],
} as const)
expectTypeOf<QueryObserverResult<string, unknown>>(result6[0])
expectTypeOf<QueryObserverResult<number, unknown>>(result6[1])
expectTypeOf<QueryObserverResult<string, BizError>>(result6[2])

// field names should be enforced - array literal
useQueries({
Expand Down
29 changes: 23 additions & 6 deletions packages/react-query/src/useQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type {
QueryClient,
QueryFunction,
QueryKey,
ThrowOnError,
} from '@tanstack/query-core'

// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
Expand Down Expand Up @@ -66,10 +67,19 @@ type GetOptions<T> =
T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseQueryOptionsForUseQueries<TQueryFnData, Error, TData, TQueryKey>
: T extends { queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey> }
? UseQueryOptionsForUseQueries<TQueryFnData, Error, TQueryFnData, TQueryKey>
? UseQueryOptionsForUseQueries<TQueryFnData, TError, TData, TQueryKey>
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseQueryOptionsForUseQueries<
TQueryFnData,
TError,
TQueryFnData,
TQueryKey
>
: // Fallback
UseQueryOptionsForUseQueries

Expand All @@ -92,10 +102,17 @@ type GetResults<T> =
T extends {
queryFn?: QueryFunction<unknown, any>
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseQueryResult<TData>
: T extends { queryFn?: QueryFunction<infer TQueryFnData, any> }
? UseQueryResult<TQueryFnData>
? UseQueryResult<TData, unknown extends TError ? DefaultError : TError>
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, any>
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseQueryResult<
TQueryFnData,
unknown extends TError ? DefaultError : TError
>
: // Fallback
UseQueryResult

Expand Down
27 changes: 21 additions & 6 deletions packages/react-query/src/useSuspenseQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
DefaultError,
QueryClient,
QueryFunction,
ThrowOnError,
} from '@tanstack/query-core'

// Avoid TS depth-limit error in case of large array literal
Expand Down Expand Up @@ -34,10 +35,14 @@ type GetSuspenseOptions<T> =
T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseSuspenseQueryOptions<TQueryFnData, Error, TData, TQueryKey>
: T extends { queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey> }
? UseSuspenseQueryOptions<TQueryFnData, Error, TQueryFnData, TQueryKey>
? UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseSuspenseQueryOptions<TQueryFnData, TError, TQueryFnData, TQueryKey>
: // Fallback
UseSuspenseQueryOptions

Expand All @@ -60,10 +65,20 @@ type GetSuspenseResults<T> =
T extends {
queryFn?: QueryFunction<unknown, any>
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseSuspenseQueryResult<TData>
: T extends { queryFn?: QueryFunction<infer TQueryFnData, any> }
? UseSuspenseQueryResult<TQueryFnData>
? UseSuspenseQueryResult<
TData,
unknown extends TError ? DefaultError : TError
>
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, any>
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseSuspenseQueryResult<
TQueryFnData,
unknown extends TError ? DefaultError : TError
>
: // Fallback
UseSuspenseQueryResult

Expand Down
24 changes: 18 additions & 6 deletions packages/solid-query/src/createQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type {
QueryFunction,
QueryKey,
QueryObserverResult,
ThrowOnError,
} from '@tanstack/query-core'

// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
Expand Down Expand Up @@ -65,12 +66,16 @@ type GetOptions<T> =
T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? CreateQueryOptionsForCreateQueries<TQueryFnData, TError, TData, TQueryKey>
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? CreateQueryOptionsForCreateQueries<TQueryFnData, Error, TData, TQueryKey>
: T extends { queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey> }
? CreateQueryOptionsForCreateQueries<
TQueryFnData,
Error,
TError,
TQueryFnData,
TQueryKey
>
Expand All @@ -96,10 +101,17 @@ type GetResults<T> =
T extends {
queryFn?: QueryFunction<unknown, any>
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? CreateQueryResult<TData>
: T extends { queryFn?: QueryFunction<infer TQueryFnData, any> }
? CreateQueryResult<TQueryFnData>
? CreateQueryResult<TData, unknown extends TError ? DefaultError : TError>
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, any>
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? CreateQueryResult<
TQueryFnData,
unknown extends TError ? DefaultError : TError
>
: // Fallback
CreateQueryResult

Expand Down
24 changes: 18 additions & 6 deletions packages/svelte-query/src/createQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
QueryKey,
QueryObserverOptions,
QueryObserverResult,
ThrowOnError,
} from '@tanstack/query-core'

// This defines the `CreateQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
Expand Down Expand Up @@ -56,17 +57,21 @@ type GetOptions<T> =
T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? QueryObserverOptionsForCreateQueries<
TQueryFnData,
Error,
TError,
TData,
TQueryKey
>
: T extends { queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey> }
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? QueryObserverOptionsForCreateQueries<
TQueryFnData,
Error,
TError,
TQueryFnData,
TQueryKey
>
Expand All @@ -92,10 +97,17 @@ type GetResults<T> =
T extends {
queryFn?: QueryFunction<unknown, any>
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? QueryObserverResult<TData>
: T extends { queryFn?: QueryFunction<infer TQueryFnData, any> }
? QueryObserverResult<TQueryFnData>
? QueryObserverResult<TData, unknown extends TError ? DefaultError : TError>
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, any>
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? QueryObserverResult<
TQueryFnData,
unknown extends TError ? DefaultError : TError
>
: // Fallback
QueryObserverResult

Expand Down
30 changes: 24 additions & 6 deletions packages/vue-query/src/useQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import { useQueryClient } from './useQueryClient'
import { cloneDeepUnref } from './utils'
import type { Ref } from 'vue-demi'
import type {
DefaultError,
QueriesObserverOptions,
QueriesPlaceholderDataFunction,
QueryFunction,
QueryKey,
QueryObserverResult,
ThrowOnError,
} from '@tanstack/query-core'
import type { UseQueryOptions } from './useQuery'
import type { QueryClient } from './queryClient'
Expand Down Expand Up @@ -63,10 +65,19 @@ type GetOptions<T> =
T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseQueryOptionsForUseQueries<TQueryFnData, Error, TData, TQueryKey>
: T extends { queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey> }
? UseQueryOptionsForUseQueries<TQueryFnData, Error, TQueryFnData, TQueryKey>
? UseQueryOptionsForUseQueries<TQueryFnData, TError, TData, TQueryKey>
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, infer TQueryKey>
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseQueryOptionsForUseQueries<
TQueryFnData,
TError,
TQueryFnData,
TQueryKey
>
: // Fallback
UseQueryOptionsForUseQueries

Expand All @@ -89,10 +100,17 @@ type GetResults<T> =
T extends {
queryFn?: QueryFunction<unknown, any>
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? QueryObserverResult<TData>
: T extends { queryFn?: QueryFunction<infer TQueryFnData, any> }
? QueryObserverResult<TQueryFnData>
? QueryObserverResult<TData, unknown extends TError ? DefaultError : TError>
: T extends {
queryFn?: QueryFunction<infer TQueryFnData, any>
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? QueryObserverResult<
TQueryFnData,
unknown extends TError ? DefaultError : TError
>
: // Fallback
QueryObserverResult

Expand Down

0 comments on commit 3ca1327

Please sign in to comment.