1
+ import type { Mutation } from './mutation'
2
+ import type { FetchOptions , Query } from './query'
1
3
import type {
2
4
DefaultError ,
3
- Enabled ,
4
5
FetchStatus ,
5
6
MutationKey ,
6
7
MutationStatus ,
7
8
QueryFunction ,
8
9
QueryKey ,
9
10
QueryOptions ,
10
- StaleTime ,
11
11
} from './types'
12
- import type { Mutation } from './mutation'
13
- import type { FetchOptions , Query } from './query'
14
12
15
13
// TYPES
16
14
@@ -79,6 +77,94 @@ export function noop(): void
79
77
export function noop ( ) : undefined
80
78
export function noop ( ) { }
81
79
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
+
82
168
export function functionalUpdate < TInput , TOutput > (
83
169
updater : Updater < TInput , TOutput > ,
84
170
input : TInput ,
@@ -96,30 +182,6 @@ export function timeUntilStale(updatedAt: number, staleTime?: number): number {
96
182
return Math . max ( updatedAt + ( staleTime || 0 ) - Date . now ( ) , 0 )
97
183
}
98
184
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
-
123
185
export function matchQuery (
124
186
filters : QueryFilters ,
125
187
query : Query < any , any , any , any > ,
0 commit comments