1+ import type { Mutation } from './mutation'
2+ import type { FetchOptions , Query } from './query'
13import type {
24 DefaultError ,
3- Enabled ,
45 FetchStatus ,
56 MutationKey ,
67 MutationStatus ,
78 QueryFunction ,
89 QueryKey ,
910 QueryOptions ,
10- StaleTime ,
1111} from './types'
12- import type { Mutation } from './mutation'
13- import type { FetchOptions , Query } from './query'
1412
1513// TYPES
1614
@@ -79,6 +77,94 @@ export function noop(): void
7977export function noop ( ) : undefined
8078export function noop ( ) { }
8179
80+ /**
81+ * Type guard that checks if a value is the function variant of a union type.
82+ *
83+ * This utility is designed for the common pattern in TanStack Query where options
84+ * can be either a direct value or a function that computes that value.
85+ *
86+ * @template T - The direct value type
87+ * @template TArgs - Array of argument types that the function variant accepts
88+ * @param value - The value to check, which can be either T or a function that returns something
89+ * @returns True if the value is a function, false otherwise. When true, TypeScript narrows the type to the function variant.
90+ *
91+ * @example
92+ * ```ts
93+ * // Basic usage with no arguments
94+ * const initialData: string | (() => string) = getValue()
95+ * if (isFunctionVariant(initialData)) {
96+ * // TypeScript knows initialData is () => string here
97+ * const result = initialData()
98+ * }
99+ * ```
100+ *
101+ * @example
102+ * ```ts
103+ * // Usage with function arguments
104+ * const staleTime: number | ((query: Query) => number) = getStaleTime()
105+ * if (isFunctionVariant<number, [Query]>(staleTime)) {
106+ * // TypeScript knows staleTime is (query: Query) => number here
107+ * const result = staleTime(query)
108+ * }
109+ * ```
110+ */
111+ function isFunctionVariant < T , TArgs extends Array < any > = [ ] > (
112+ value : T | ( ( ...args : TArgs ) => any ) ,
113+ ) : value is ( ...args : TArgs ) => any {
114+ return typeof value === 'function'
115+ }
116+
117+ /**
118+ * Resolves a value that can either be a direct value or a function that computes the value.
119+ *
120+ * This utility eliminates the need for repetitive `typeof value === 'function'` checks
121+ * throughout the codebase and provides a clean way to handle the common pattern where
122+ * options can be static values or dynamic functions.
123+ *
124+ * @template T - The type of the resolved value
125+ * @template TArgs - Array of argument types when resolving function variants
126+ * @param value - Either a direct value of type T or a function that returns T
127+ * @param args - Arguments to pass to the function if value is a function
128+ * @returns The resolved value of type T
129+ *
130+ * @example
131+ * ```ts
132+ * // Zero-argument function resolution (like initialData)
133+ * const initialData: string | (() => string) = 'hello'
134+ * const resolved = resolveValueOrFunction(initialData) // 'hello'
135+ *
136+ * const initialDataFn: string | (() => string) = () => 'world'
137+ * const resolved2 = resolveValueOrFunction(initialDataFn) // 'world'
138+ * ```
139+ *
140+ * @example
141+ * ```ts
142+ * // Function with arguments (like staleTime, retryDelay)
143+ * const staleTime: number | ((query: Query) => number) = (query) => query.state.dataUpdatedAt + 5000
144+ * const resolved = resolveValueOrFunction(staleTime, query) // number
145+ *
146+ * const retryDelay: number | ((failureCount: number, error: Error) => number) = 1000
147+ * const resolved2 = resolveValueOrFunction(retryDelay, 3, new Error()) // 1000
148+ * ```
149+ *
150+ * @example
151+ * ```ts
152+ * // Replaces verbose patterns like:
153+ * // const delay = typeof retryDelay === 'function'
154+ * // ? retryDelay(failureCount, error)
155+ * // : retryDelay
156+ *
157+ * // With:
158+ * const delay = resolveValueOrFunction(retryDelay, failureCount, error)
159+ * ```
160+ */
161+ export function resolveValueOrFunction < T , TArgs extends Array < any > > (
162+ value : T | ( ( ...args : TArgs ) => T ) ,
163+ ...args : TArgs
164+ ) : T {
165+ return isFunctionVariant ( value ) ? value ( ...args ) : value
166+ }
167+
82168export function functionalUpdate < TInput , TOutput > (
83169 updater : Updater < TInput , TOutput > ,
84170 input : TInput ,
@@ -96,30 +182,6 @@ export function timeUntilStale(updatedAt: number, staleTime?: number): number {
96182 return Math . max ( updatedAt + ( staleTime || 0 ) - Date . now ( ) , 0 )
97183}
98184
99- export function resolveStaleTime <
100- TQueryFnData = unknown ,
101- TError = DefaultError ,
102- TData = TQueryFnData ,
103- TQueryKey extends QueryKey = QueryKey ,
104- > (
105- staleTime : undefined | StaleTime < TQueryFnData , TError , TData , TQueryKey > ,
106- query : Query < TQueryFnData , TError , TData , TQueryKey > ,
107- ) : number | undefined {
108- return typeof staleTime === 'function' ? staleTime ( query ) : staleTime
109- }
110-
111- export function resolveEnabled <
112- TQueryFnData = unknown ,
113- TError = DefaultError ,
114- TData = TQueryFnData ,
115- TQueryKey extends QueryKey = QueryKey ,
116- > (
117- enabled : undefined | Enabled < TQueryFnData , TError , TData , TQueryKey > ,
118- query : Query < TQueryFnData , TError , TData , TQueryKey > ,
119- ) : boolean | undefined {
120- return typeof enabled === 'function' ? enabled ( query ) : enabled
121- }
122-
123185export function matchQuery (
124186 filters : QueryFilters ,
125187 query : Query < any , any , any , any > ,
0 commit comments