Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/core/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import {
noop,
replaceEqualDeep,
timeUntilStale,
ensureQueryKeyArray,
} from './utils'
import type {
InitialDataFunction,
QueryKey,
QueryOptions,
QueryStatus,
QueryFunctionContext,
EnsuredQueryKey,
} from './types'
import type { QueryCache } from './queryCache'
import type { QueryObserver } from './queryObserver'
Expand Down Expand Up @@ -58,8 +60,8 @@ export interface FetchContext<
> {
fetchFn: () => unknown | Promise<unknown>
fetchOptions?: FetchOptions
options: QueryOptions<TQueryFnData, TError, TData, TQueryKey>
queryKey: TQueryKey
options: QueryOptions<TQueryFnData, TError, TData, any>
queryKey: EnsuredQueryKey<TQueryKey>
state: QueryState<TData, TError>
}

Expand Down Expand Up @@ -380,9 +382,11 @@ export class Query<
}
}

const queryKey = ensureQueryKeyArray(this.queryKey)

// Create query function context
const queryFnContext: QueryFunctionContext<TQueryKey> = {
queryKey: this.queryKey,
queryKey,
pageParam: undefined,
}

Expand All @@ -393,10 +397,10 @@ export class Query<
: Promise.reject('Missing queryFn')

// Trigger behavior hook
const context: FetchContext<TQueryFnData, TError, TData, any> = {
const context: FetchContext<TQueryFnData, TError, TData, TQueryKey> = {
fetchOptions,
options: this.options,
queryKey: this.queryKey,
queryKey: queryKey,
state: this.state,
fetchFn,
}
Expand Down
7 changes: 4 additions & 3 deletions src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import type { RetryValue, RetryDelayValue } from './retryer'
import type { QueryFilters } from './utils'

export type QueryKey = string | readonly unknown[]
export type EnsuredQueryKey<T extends QueryKey> = T extends string
? [T]
: Exclude<T, string>

export type QueryFunction<
T = unknown,
Expand All @@ -14,14 +17,12 @@ export interface QueryFunctionContext<
TQueryKey extends QueryKey = QueryKey,
TPageParam = any
> {
queryKey: TQueryKey
queryKey: EnsuredQueryKey<TQueryKey>
pageParam?: TPageParam
}

export type InitialDataFunction<T> = () => T | undefined

export type InitialStaleFunction = () => boolean

export type PlaceholderDataFunction<TResult> = () => TResult | undefined

export type QueryKeyHashFunction<TQueryKey extends QueryKey> = (
Expand Down
13 changes: 9 additions & 4 deletions src/core/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Mutation } from './mutation'
import type { Query } from './query'
import { EnsuredQueryKey } from './types'
import type {
MutationFunction,
MutationKey,
Expand Down Expand Up @@ -88,8 +89,12 @@ export function isValidTimeout(value: any): value is number {
return typeof value === 'number' && value >= 0 && value !== Infinity
}

export function ensureArray<T>(value: T | T[]): T[] {
return Array.isArray(value) ? value : [value]
export function ensureQueryKeyArray<T extends QueryKey>(
value: T
): EnsuredQueryKey<T> {
return (Array.isArray(value)
? value
: ([value] as unknown)) as EnsuredQueryKey<T>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couldn't get the type to work any other way, I think Array.isArray is not smart enough. Do you know a better way @boschni ?

}

export function difference<T>(array1: T[], array2: T[]): T[] {
Expand Down Expand Up @@ -256,7 +261,7 @@ export function hashQueryKeyByOptions<TQueryKey extends QueryKey = QueryKey>(
* Default query keys hash function.
*/
export function hashQueryKey(queryKey: QueryKey): string {
const asArray = Array.isArray(queryKey) ? queryKey : [queryKey]
const asArray = ensureQueryKeyArray(queryKey)
return stableValueHash(asArray)
}

Expand All @@ -280,7 +285,7 @@ export function stableValueHash(value: any): string {
* Checks if key `b` partially matches with key `a`.
*/
export function partialMatchKey(a: QueryKey, b: QueryKey): boolean {
return partialDeepEqual(ensureArray(a), ensureArray(b))
return partialDeepEqual(ensureQueryKeyArray(a), ensureQueryKeyArray(b))
}

/**
Expand Down
14 changes: 12 additions & 2 deletions src/react/tests/useQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,25 @@ describe('useQuery', () => {
type MyData = number
type MyQueryKey = readonly ['my-data', number]

const getMyData: QueryFunction<MyData, MyQueryKey> = async ({
const getMyDataArrayKey: QueryFunction<MyData, MyQueryKey> = async ({
queryKey: [, n],
}) => {
return n + 42
}

useQuery({
queryKey: ['my-data', 100],
queryFn: getMyData,
queryFn: getMyDataArrayKey,
})

const getMyDataStringKey: QueryFunction<MyData, '1'> = async context => {
expectType<['1']>(context.queryKey)
return Number(context.queryKey[0]) + 42
}

useQuery({
queryKey: '1',
queryFn: getMyDataStringKey,
})
}
})
Expand Down