Skip to content

Commit

Permalink
refactor(*): improved type inference for useQueries with skipToken (#…
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
gwansikk and TkDodo committed Jun 4, 2024
1 parent 96aa461 commit 6f08200
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 190 deletions.
52 changes: 15 additions & 37 deletions packages/angular-query-experimental/src/inject-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import type {
QueryKey,
QueryObserverOptions,
QueryObserverResult,
SkipToken,
ThrowOnError,
} from '@tanstack/query-core'

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

// Widen the type of the symbol to enable type inference even if skipToken is not immutable.
type SkipTokenForUseQueries = symbol

type GetOptions<T> =
// Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
T extends {
Expand All @@ -56,30 +58,18 @@ type GetOptions<T> =
T extends {
queryFn?:
| QueryFunction<infer TQueryFnData, infer TQueryKey>
| SkipToken
| SkipTokenForUseQueries
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? QueryObserverOptionsForCreateQueries<
TQueryFnData,
TError,
TData,
unknown extends TError ? DefaultError : TError,
unknown extends TData ? TQueryFnData : TData,
TQueryKey
>
: T extends {
queryFn?:
| QueryFunction<infer TQueryFnData, infer TQueryKey>
| SkipToken
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? QueryObserverOptionsForCreateQueries<
TQueryFnData,
TError,
TQueryFnData,
TQueryKey
>
: // Fallback
QueryObserverOptionsForCreateQueries
: // Fallback
QueryObserverOptionsForCreateQueries

type GetResults<T> =
// Part 1: responsible for mapping explicit type parameter to function result, if object
Expand All @@ -98,24 +88,18 @@ type GetResults<T> =
? QueryObserverResult<TQueryFnData>
: // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
T extends {
queryFn?: QueryFunction<unknown, any>
queryFn?:
| QueryFunction<infer TQueryFnData, any>
| SkipTokenForUseQueries
select: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? QueryObserverResult<
TData,
unknown extends TData ? TQueryFnData : 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
: // Fallback
QueryObserverResult

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

return defaultedOptions as QueryObserverOptions<
unknown,
Error,
unknown,
unknown,
QueryKey
>
return defaultedOptions as QueryObserverOptions
})
})

Expand Down
7 changes: 4 additions & 3 deletions packages/react-query/src/__tests__/useQueries.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { skipToken } from '..'
import { useQueries } from '../useQueries'
import { queryOptions } from '../queryOptions'
import type { OmitKeyof } from '..'
import type { UseQueryOptions } from '../types'
import type { UseQueryOptions, UseQueryResult } from '../types'

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

const data = queryResults[0].data
const firstResult = queryResults[0]

expectTypeOf(data).toEqualTypeOf<number | undefined>()
expectTypeOf(firstResult).toEqualTypeOf<UseQueryResult<number, Error>>()
expectTypeOf(firstResult.data).toEqualTypeOf<number | undefined>()
})
})
53 changes: 14 additions & 39 deletions packages/react-query/src/useQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import type {
QueryFunction,
QueryKey,
QueryObserverOptions,
SkipToken,
ThrowOnError,
} from '@tanstack/query-core'

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

// Widen the type of the symbol to enable type inference even if skipToken is not immutable.
type SkipTokenForUseQueries = symbol

type GetUseQueryOptionsForUseQueries<T> =
// Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
T extends {
Expand All @@ -78,30 +80,18 @@ type GetUseQueryOptionsForUseQueries<T> =
T extends {
queryFn?:
| QueryFunction<infer TQueryFnData, infer TQueryKey>
| SkipToken
| SkipTokenForUseQueries
select?: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseQueryOptionsForUseQueries<
TQueryFnData,
TError,
TData,
unknown extends TError ? DefaultError : TError,
unknown extends TData ? TQueryFnData : TData,
TQueryKey
>
: T extends {
queryFn?:
| QueryFunction<infer TQueryFnData, infer TQueryKey>
| SkipToken
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseQueryOptionsForUseQueries<
TQueryFnData,
TError,
TQueryFnData,
TQueryKey
>
: // Fallback
UseQueryOptionsForUseQueries
: // Fallback
UseQueryOptionsForUseQueries

// A defined initialData setting should return a DefinedUseQueryResult rather than UseQueryResult
type GetDefinedOrUndefinedQueryResult<T, TData, TError = unknown> = T extends {
Expand Down Expand Up @@ -137,7 +127,9 @@ type GetUseQueryResult<T> =
? GetDefinedOrUndefinedQueryResult<T, TQueryFnData>
: // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
T extends {
queryFn?: QueryFunction<infer TQueryFnData, any> | SkipToken
queryFn?:
| QueryFunction<infer TQueryFnData, any>
| SkipTokenForUseQueries
select?: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
Expand All @@ -146,19 +138,8 @@ type GetUseQueryResult<T> =
unknown extends TData ? TQueryFnData : TData,
unknown extends TError ? DefaultError : TError
>
: T extends {
queryFn?:
| QueryFunction<infer TQueryFnData, any>
| SkipToken
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? GetDefinedOrUndefinedQueryResult<
T,
TQueryFnData,
unknown extends TError ? DefaultError : TError
>
: // Fallback
UseQueryResult
: // Fallback
UseQueryResult

/**
* QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
Expand Down Expand Up @@ -260,13 +241,7 @@ export function useQueries<
() =>
queries.map((opts) => {
const defaultedOptions = client.defaultQueryOptions(
opts as QueryObserverOptions<
unknown,
Error,
unknown,
unknown,
QueryKey
>,
opts as QueryObserverOptions,
)

// Make sure the results are already in fetching state before subscribing or updating options
Expand Down
56 changes: 22 additions & 34 deletions packages/solid-query/src/createQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import type {
QueriesPlaceholderDataFunction,
QueryFunction,
QueryKey,
QueryObserverOptions,
QueryObserverResult,
SkipToken,
ThrowOnError,
} from '@tanstack/query-core'

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

// Widen the type of the symbol to enable type inference even if skipToken is not immutable.
type SkipTokenForUseQueries = symbol

type GetOptions<T> =
// Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
T extends {
Expand All @@ -75,30 +78,18 @@ type GetOptions<T> =
T extends {
queryFn?:
| QueryFunction<infer TQueryFnData, infer TQueryKey>
| SkipToken
| SkipTokenForUseQueries
select?: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? CreateQueryOptionsForCreateQueries<
TQueryFnData,
TError,
TData,
unknown extends TError ? DefaultError : TError,
unknown extends TData ? TQueryFnData : TData,
TQueryKey
>
: T extends {
queryFn?:
| QueryFunction<infer TQueryFnData, infer TQueryKey>
| SkipToken
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? CreateQueryOptionsForCreateQueries<
TQueryFnData,
TError,
TQueryFnData,
TQueryKey
>
: // Fallback
CreateQueryOptionsForCreateQueries
: // Fallback
CreateQueryOptionsForCreateQueries

type GetResults<T> =
// Part 1: responsible for mapping explicit type parameter to function result, if object
Expand All @@ -117,24 +108,18 @@ type GetResults<T> =
? CreateQueryResult<TQueryFnData>
: // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
T extends {
queryFn?: QueryFunction<infer TQueryFnData, any>
queryFn?:
| QueryFunction<infer TQueryFnData, any>
| SkipTokenForUseQueries
select?: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? CreateQueryResult<
unknown extends TData ? TQueryFnData : 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
: // Fallback
CreateQueryResult

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

const defaultedQueries: QueriesOptions<any> = createMemo(() =>
const defaultedQueries = createMemo(() =>
queriesOptions().queries.map((options) =>
mergeProps(client().defaultQueryOptions(options), {
get _optimisticResults() {
return isRestoring() ? 'isRestoring' : 'optimistic'
mergeProps(
client().defaultQueryOptions(options as QueryObserverOptions),
{
get _optimisticResults() {
return isRestoring() ? 'isRestoring' : 'optimistic'
},
},
}),
),
),
)

Expand Down
Loading

0 comments on commit 6f08200

Please sign in to comment.