@@ -15,20 +15,15 @@ import {
15
15
useQuery ,
16
16
useSuspenseQuery ,
17
17
useInfiniteQuery ,
18
- } from ' @tanstack/react-query' ;
18
+ } from " @tanstack/react-query" ;
19
19
import type {
20
20
ClientMethod ,
21
21
FetchResponse ,
22
22
MaybeOptionalInit ,
23
23
Client as FetchClient ,
24
24
DefaultParamsOption ,
25
- } from 'openapi-fetch' ;
26
- import type {
27
- HttpMethod ,
28
- MediaType ,
29
- PathsWithMethod ,
30
- RequiredKeysOf ,
31
- } from 'openapi-typescript-helpers' ;
25
+ } from "openapi-fetch" ;
26
+ import type { HttpMethod , MediaType , PathsWithMethod , RequiredKeysOf } from "openapi-typescript-helpers" ;
32
27
33
28
// Helper type to dynamically infer the type from the `select` property
34
29
type InferSelectReturnType < TData , TSelect > = TSelect extends ( data : TData ) => infer R ? R : TData ;
@@ -42,22 +37,19 @@ export type QueryKey<
42
37
Init = MaybeOptionalInit < Paths [ Path ] , Method > ,
43
38
> = Init extends undefined ? readonly [ Method , Path ] : readonly [ Method , Path , Init ] ;
44
39
45
- export type QueryOptionsFunction <
46
- Paths extends Record < string , Record < HttpMethod , { } > > ,
47
- Media extends MediaType ,
48
- > = <
40
+ export type QueryOptionsFunction < Paths extends Record < string , Record < HttpMethod , { } > > , Media extends MediaType > = <
49
41
Method extends HttpMethod ,
50
42
Path extends PathsWithMethod < Paths , Method > ,
51
43
Init extends MaybeOptionalInit < Paths [ Path ] , Method > ,
52
44
Response extends Required < FetchResponse < Paths [ Path ] [ Method ] , Init , Media > > , // note: Required is used to avoid repeating NonNullable in UseQuery types
53
45
Options extends Omit <
54
46
UseQueryOptions <
55
- Response [ ' data' ] ,
56
- Response [ ' error' ] ,
57
- InferSelectReturnType < Response [ ' data' ] , Options [ ' select' ] > ,
47
+ Response [ " data" ] ,
48
+ Response [ " error" ] ,
49
+ InferSelectReturnType < Response [ " data" ] , Options [ " select" ] > ,
58
50
QueryKey < Paths , Method , Path >
59
51
> ,
60
- ' queryKey' | ' queryFn'
52
+ " queryKey" | " queryFn"
61
53
> ,
62
54
> (
63
55
method : Method ,
@@ -68,129 +60,113 @@ export type QueryOptionsFunction<
68
60
) => NoInfer <
69
61
Omit <
70
62
UseQueryOptions <
71
- Response [ ' data' ] ,
72
- Response [ ' error' ] ,
73
- InferSelectReturnType < Response [ ' data' ] , Options [ ' select' ] > ,
63
+ Response [ " data" ] ,
64
+ Response [ " error" ] ,
65
+ InferSelectReturnType < Response [ " data" ] , Options [ " select" ] > ,
74
66
QueryKey < Paths , Method , Path >
75
67
> ,
76
- ' queryFn'
68
+ " queryFn"
77
69
> & {
78
70
queryFn : Exclude <
79
71
UseQueryOptions <
80
- Response [ ' data' ] ,
81
- Response [ ' error' ] ,
82
- InferSelectReturnType < Response [ ' data' ] , Options [ ' select' ] > ,
72
+ Response [ " data" ] ,
73
+ Response [ " error" ] ,
74
+ InferSelectReturnType < Response [ " data" ] , Options [ " select" ] > ,
83
75
QueryKey < Paths , Method , Path >
84
- > [ ' queryFn' ] ,
76
+ > [ " queryFn" ] ,
85
77
SkipToken | undefined
86
78
> ;
87
79
}
88
80
> ;
89
81
90
- export type UseQueryMethod <
91
- Paths extends Record < string , Record < HttpMethod , { } > > ,
92
- Media extends MediaType ,
93
- > = <
82
+ export type UseQueryMethod < Paths extends Record < string , Record < HttpMethod , { } > > , Media extends MediaType > = <
94
83
Method extends HttpMethod ,
95
84
Path extends PathsWithMethod < Paths , Method > ,
96
85
Init extends MaybeOptionalInit < Paths [ Path ] , Method > ,
97
86
Response extends Required < FetchResponse < Paths [ Path ] [ Method ] , Init , Media > > , // note: Required is used to avoid repeating NonNullable in UseQuery types
98
87
Options extends Omit <
99
88
UseQueryOptions <
100
- Response [ ' data' ] ,
101
- Response [ ' error' ] ,
102
- InferSelectReturnType < Response [ ' data' ] , Options [ ' select' ] > ,
89
+ Response [ " data" ] ,
90
+ Response [ " error" ] ,
91
+ InferSelectReturnType < Response [ " data" ] , Options [ " select" ] > ,
103
92
QueryKey < Paths , Method , Path >
104
93
> ,
105
- ' queryKey' | ' queryFn'
94
+ " queryKey" | " queryFn"
106
95
> ,
107
96
> (
108
97
method : Method ,
109
98
url : Path ,
110
99
...[ init , options , queryClient ] : RequiredKeysOf < Init > extends never
111
100
? [ InitWithUnknowns < Init > ?, Options ?, QueryClient ?]
112
101
: [ InitWithUnknowns < Init > , Options ?, QueryClient ?]
113
- ) => UseQueryResult < InferSelectReturnType < Response [ ' data' ] , Options [ ' select' ] > , Response [ ' error' ] > ;
102
+ ) => UseQueryResult < InferSelectReturnType < Response [ " data" ] , Options [ " select" ] > , Response [ " error" ] > ;
114
103
115
- export type UseInfiniteQueryMethod <
116
- Paths extends Record < string , Record < HttpMethod , { } > > ,
117
- Media extends MediaType ,
118
- > = <
104
+ // Helper type to infer TPageParam type
105
+ type InferPageParamType < T > = T extends { initialPageParam : infer P } ? P : unknown ;
106
+
107
+ export type UseInfiniteQueryMethod < Paths extends Record < string , Record < HttpMethod , { } > > , Media extends MediaType > = <
119
108
Method extends HttpMethod ,
120
109
Path extends PathsWithMethod < Paths , Method > ,
121
110
Init extends MaybeOptionalInit < Paths [ Path ] , Method > ,
122
111
Response extends Required < FetchResponse < Paths [ Path ] [ Method ] , Init , Media > > ,
123
- Select = undefined ,
124
112
Options extends Omit <
125
113
UseInfiniteQueryOptions <
126
- Response [ ' data' ] ,
127
- Response [ ' error' ] ,
128
- InferSelectReturnType < InfiniteData < Response [ ' data' ] > , Select > ,
114
+ Response [ " data" ] ,
115
+ Response [ " error" ] ,
116
+ InferSelectReturnType < InfiniteData < Response [ " data" ] > , Options [ "select" ] > ,
129
117
QueryKey < Paths , Method , Path > ,
130
- unknown
118
+ InferPageParamType < Options >
131
119
> ,
132
- ' queryKey' | ' queryFn'
120
+ " queryKey" | " queryFn"
133
121
> & {
134
122
pageParamName ?: string ;
135
- select ?: Select ;
136
- } = any ,
123
+ initialPageParam : InferPageParamType < Options > ;
124
+ } ,
137
125
> (
138
126
method : Method ,
139
127
url : Path ,
140
128
init : InitWithUnknowns < Init > ,
141
129
options : Options ,
142
- queryClient ?: QueryClient
130
+ queryClient ?: QueryClient ,
143
131
) => UseInfiniteQueryResult <
144
- InferSelectReturnType < InfiniteData < Response [ ' data' ] > , Select > ,
145
- Response [ ' error' ]
132
+ InferSelectReturnType < InfiniteData < Response [ " data" ] > , Options [ "select" ] > ,
133
+ Response [ " error" ]
146
134
> ;
147
135
148
- export type UseSuspenseQueryMethod <
149
- Paths extends Record < string , Record < HttpMethod , { } > > ,
150
- Media extends MediaType ,
151
- > = <
136
+ export type UseSuspenseQueryMethod < Paths extends Record < string , Record < HttpMethod , { } > > , Media extends MediaType > = <
152
137
Method extends HttpMethod ,
153
138
Path extends PathsWithMethod < Paths , Method > ,
154
139
Init extends MaybeOptionalInit < Paths [ Path ] , Method > ,
155
140
Response extends Required < FetchResponse < Paths [ Path ] [ Method ] , Init , Media > > , // note: Required is used to avoid repeating NonNullable in UseQuery types
156
141
Options extends Omit <
157
142
UseSuspenseQueryOptions <
158
- Response [ ' data' ] ,
159
- Response [ ' error' ] ,
160
- InferSelectReturnType < Response [ ' data' ] , Options [ ' select' ] > ,
143
+ Response [ " data" ] ,
144
+ Response [ " error" ] ,
145
+ InferSelectReturnType < Response [ " data" ] , Options [ " select" ] > ,
161
146
QueryKey < Paths , Method , Path >
162
147
> ,
163
- ' queryKey' | ' queryFn'
148
+ " queryKey" | " queryFn"
164
149
> ,
165
150
> (
166
151
method : Method ,
167
152
url : Path ,
168
153
...[ init , options , queryClient ] : RequiredKeysOf < Init > extends never
169
154
? [ InitWithUnknowns < Init > ?, Options ?, QueryClient ?]
170
155
: [ InitWithUnknowns < Init > , Options ?, QueryClient ?]
171
- ) => UseSuspenseQueryResult <
172
- InferSelectReturnType < Response [ 'data' ] , Options [ 'select' ] > ,
173
- Response [ 'error' ]
174
- > ;
156
+ ) => UseSuspenseQueryResult < InferSelectReturnType < Response [ "data" ] , Options [ "select" ] > , Response [ "error" ] > ;
175
157
176
- export type UseMutationMethod <
177
- Paths extends Record < string , Record < HttpMethod , { } > > ,
178
- Media extends MediaType ,
179
- > = <
158
+ export type UseMutationMethod < Paths extends Record < string , Record < HttpMethod , { } > > , Media extends MediaType > = <
180
159
Method extends HttpMethod ,
181
160
Path extends PathsWithMethod < Paths , Method > ,
182
161
Init extends MaybeOptionalInit < Paths [ Path ] , Method > ,
183
162
Response extends Required < FetchResponse < Paths [ Path ] [ Method ] , Init , Media > > , // note: Required is used to avoid repeating NonNullable in UseQuery types
184
- Options extends Omit <
185
- UseMutationOptions < Response [ 'data' ] , Response [ 'error' ] , Init > ,
186
- 'mutationKey' | 'mutationFn'
187
- > ,
163
+ Options extends Omit < UseMutationOptions < Response [ "data" ] , Response [ "error" ] , Init > , "mutationKey" | "mutationFn" > ,
188
164
> (
189
165
method : Method ,
190
166
url : Path ,
191
167
options ?: Options ,
192
- queryClient ?: QueryClient
193
- ) => UseMutationResult < Response [ ' data' ] , Response [ ' error' ] , Init > ;
168
+ queryClient ?: QueryClient ,
169
+ ) => UseMutationResult < Response [ " data" ] , Response [ " error" ] , Init > ;
194
170
195
171
export interface OpenapiQueryClient < Paths extends { } , Media extends MediaType = MediaType > {
196
172
queryOptions : QueryOptionsFunction < Paths , Media > ;
@@ -207,62 +183,59 @@ export type MethodResponse<
207
183
? PathsWithMethod < Paths , Method >
208
184
: never ,
209
185
Options = object ,
210
- > =
211
- CreatedClient extends OpenapiQueryClient <
212
- infer Paths extends { [ key : string ] : any } ,
213
- infer Media extends MediaType
214
- >
215
- ? NonNullable < FetchResponse < Paths [ Path ] [ Method ] , Options , Media > [ 'data' ] >
216
- : never ;
186
+ > = CreatedClient extends OpenapiQueryClient < infer Paths extends { [ key : string ] : any } , infer Media extends MediaType >
187
+ ? NonNullable < FetchResponse < Paths [ Path ] [ Method ] , Options , Media > [ "data" ] >
188
+ : never ;
217
189
218
190
// TODO: Add the ability to bring queryClient as argument
219
191
export default function createClient < Paths extends { } , Media extends MediaType = MediaType > (
220
- client : FetchClient < Paths , Media >
192
+ client : FetchClient < Paths , Media > ,
221
193
) : OpenapiQueryClient < Paths , Media > {
222
194
const queryFn = async < Method extends HttpMethod , Path extends PathsWithMethod < Paths , Method > > ( {
223
195
queryKey : [ method , path , init ] ,
224
196
signal,
225
197
} : QueryFunctionContext < QueryKey < Paths , Method , Path > > ) => {
226
198
const mth = method . toUpperCase ( ) as Uppercase < typeof method > ;
227
199
const fn = client [ mth ] as ClientMethod < Paths , typeof method , Media > ;
228
- const { data, error, response } = await fn ( path , { signal, ...( init as any ) } ) ; // TODO: find a way to avoid as any
200
+ const { data, error, response } = await fn ( path , {
201
+ signal,
202
+ ...( init as any ) ,
203
+ } ) ; // TODO: find a way to avoid as any
229
204
if ( error ) {
230
205
throw error ;
231
206
}
232
- if ( response . status === 204 || response . headers . get ( ' Content-Length' ) === '0' ) {
207
+ if ( response . status === 204 || response . headers . get ( " Content-Length" ) === "0" ) {
233
208
return data ?? null ;
234
209
}
235
210
236
211
return data ;
237
212
} ;
238
213
239
214
const queryOptions : QueryOptionsFunction < Paths , Media > = ( method , path , ...[ init , options ] ) => ( {
240
- queryKey : ( init === undefined
241
- ? ( [ method , path ] as const )
242
- : ( [ method , path , init ] as const ) ) as QueryKey < Paths , typeof method , typeof path > ,
215
+ queryKey : ( init === undefined ? ( [ method , path ] as const ) : ( [ method , path , init ] as const ) ) as QueryKey <
216
+ Paths ,
217
+ typeof method ,
218
+ typeof path
219
+ > ,
243
220
queryFn,
244
221
...options ,
245
222
} ) ;
246
223
247
224
return {
248
225
queryOptions,
249
226
useQuery : ( method , path , ...[ init , options , queryClient ] ) =>
250
- useQuery (
251
- queryOptions ( method , path , init as InitWithUnknowns < typeof init > , options ) ,
252
- queryClient
253
- ) ,
227
+ useQuery ( queryOptions ( method , path , init as InitWithUnknowns < typeof init > , options ) , queryClient ) ,
254
228
useSuspenseQuery : ( method , path , ...[ init , options , queryClient ] ) =>
255
- useSuspenseQuery (
256
- queryOptions ( method , path , init as InitWithUnknowns < typeof init > , options ) ,
257
- queryClient
258
- ) ,
229
+ useSuspenseQuery ( queryOptions ( method , path , init as InitWithUnknowns < typeof init > , options ) , queryClient ) ,
259
230
useInfiniteQuery : ( method , path , init , options , queryClient ) => {
260
- const { pageParamName = ' cursor' , ...restOptions } = options ;
231
+ const { pageParamName = " cursor" , initialPageParam , ...restOptions } = options ;
261
232
const { queryKey } = queryOptions ( method , path , init ) ;
233
+
262
234
return useInfiniteQuery (
263
235
{
264
236
queryKey,
265
- queryFn : async ( { queryKey : [ method , path , init ] , pageParam = 0 , signal } ) => {
237
+ initialPageParam,
238
+ queryFn : async ( { queryKey : [ method , path , init ] , pageParam, signal } ) => {
266
239
const mth = method . toUpperCase ( ) as Uppercase < typeof method > ;
267
240
const fn = client [ mth ] as ClientMethod < Paths , typeof method , Media > ;
268
241
const mergedInit = {
@@ -285,7 +258,7 @@ export default function createClient<Paths extends {}, Media extends MediaType =
285
258
} ,
286
259
...restOptions ,
287
260
} ,
288
- queryClient
261
+ queryClient ,
289
262
) ;
290
263
} ,
291
264
useMutation : ( method , path , options , queryClient ) =>
@@ -304,7 +277,7 @@ export default function createClient<Paths extends {}, Media extends MediaType =
304
277
} ,
305
278
...options ,
306
279
} ,
307
- queryClient
280
+ queryClient ,
308
281
) ,
309
282
} ;
310
283
}
0 commit comments