openapi-typesafe-helpers 1.0.0-rc.1 → 1.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,15 @@ Type helpers shared by `openapi-typesafe-fetch` and `openapi-typesafe-react-quer
6
6
  A maintained successor to `openapi-typescript-helpers` (see the [repository README](../../README.md)).
7
7
  Most projects do not need to install it directly.
8
8
 
9
+ > **Release candidate.** The current version is a 1.0.0 release candidate (`1.0.0-rc.N`);
10
+ > names and output can still change before 1.0.0.
11
+
12
+ ## Versioning
13
+
14
+ Semantic versioning from 1.0.0, with one version for all openapi-typesafe packages. What the
15
+ version promises, and what may grow in a minor release, is listed under
16
+ [Versioning](https://github.com/openapi-typesafe/openapi-typesafe/blob/main/docs/compatibility.md#versioning).
17
+
9
18
  ## License
10
19
 
11
20
  [MIT](./LICENSE)
package/dist/index.d.cts CHANGED
@@ -1,181 +1,286 @@
1
- type HttpMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace" | "query";
1
+ type HttpMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"
2
+ /** OpenAPI 3.2: a safe, idempotent request with a body. */
3
+ | "query";
4
+ /** 2XX statuses */
2
5
  type OkStatus = 200 | 201 | 202 | 203 | 204 | 206 | 207 | "2XX";
6
+ /** 4XX and 5XX statuses */
3
7
  type ErrorStatus = 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 | "5XX" | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 444 | 450 | 451 | 497 | 498 | 499 | "4XX" | "default";
8
+ /** Get a union of OK Statuses */
4
9
  type OKStatusUnion<T> = FilterKeys<T, OkStatus>;
10
+ /** Get first error status, in order */
5
11
  type FirstErrorStatus<T> = T extends {
6
- 500: any;
12
+ 500: unknown;
7
13
  } ? T[500] : T extends {
8
- 501: any;
14
+ 501: unknown;
9
15
  } ? T[501] : T extends {
10
- 502: any;
16
+ 502: unknown;
11
17
  } ? T[502] : T extends {
12
- 503: any;
18
+ 503: unknown;
13
19
  } ? T[503] : T extends {
14
- 504: any;
20
+ 504: unknown;
15
21
  } ? T[504] : T extends {
16
- 505: any;
22
+ 505: unknown;
17
23
  } ? T[505] : T extends {
18
- 506: any;
24
+ 506: unknown;
19
25
  } ? T[506] : T extends {
20
- 507: any;
26
+ 507: unknown;
21
27
  } ? T[507] : T extends {
22
- 508: any;
28
+ 508: unknown;
23
29
  } ? T[508] : T extends {
24
- 510: any;
30
+ 510: unknown;
25
31
  } ? T[510] : T extends {
26
- 511: any;
32
+ 511: unknown;
27
33
  } ? T[511] : T extends {
28
- "5XX": any;
34
+ "5XX": unknown;
29
35
  } ? T["5XX"] : T extends {
30
- 400: any;
36
+ 400: unknown;
31
37
  } ? T[400] : T extends {
32
- 401: any;
38
+ 401: unknown;
33
39
  } ? T[401] : T extends {
34
- 402: any;
40
+ 402: unknown;
35
41
  } ? T[402] : T extends {
36
- 403: any;
42
+ 403: unknown;
37
43
  } ? T[403] : T extends {
38
- 404: any;
44
+ 404: unknown;
39
45
  } ? T[404] : T extends {
40
- 405: any;
46
+ 405: unknown;
41
47
  } ? T[405] : T extends {
42
- 406: any;
48
+ 406: unknown;
43
49
  } ? T[406] : T extends {
44
- 407: any;
50
+ 407: unknown;
45
51
  } ? T[407] : T extends {
46
- 408: any;
52
+ 408: unknown;
47
53
  } ? T[408] : T extends {
48
- 409: any;
54
+ 409: unknown;
49
55
  } ? T[409] : T extends {
50
- 410: any;
56
+ 410: unknown;
51
57
  } ? T[410] : T extends {
52
- 411: any;
58
+ 411: unknown;
53
59
  } ? T[411] : T extends {
54
- 412: any;
60
+ 412: unknown;
55
61
  } ? T[412] : T extends {
56
- 413: any;
62
+ 413: unknown;
57
63
  } ? T[413] : T extends {
58
- 414: any;
64
+ 414: unknown;
59
65
  } ? T[414] : T extends {
60
- 415: any;
66
+ 415: unknown;
61
67
  } ? T[415] : T extends {
62
- 416: any;
68
+ 416: unknown;
63
69
  } ? T[416] : T extends {
64
- 417: any;
70
+ 417: unknown;
65
71
  } ? T[417] : T extends {
66
- 418: any;
72
+ 418: unknown;
67
73
  } ? T[418] : T extends {
68
- 420: any;
74
+ 420: unknown;
69
75
  } ? T[420] : T extends {
70
- 421: any;
76
+ 421: unknown;
71
77
  } ? T[421] : T extends {
72
- 422: any;
78
+ 422: unknown;
73
79
  } ? T[422] : T extends {
74
- 423: any;
80
+ 423: unknown;
75
81
  } ? T[423] : T extends {
76
- 424: any;
82
+ 424: unknown;
77
83
  } ? T[424] : T extends {
78
- 425: any;
84
+ 425: unknown;
79
85
  } ? T[425] : T extends {
80
- 426: any;
86
+ 426: unknown;
81
87
  } ? T[426] : T extends {
82
- 427: any;
88
+ 427: unknown;
83
89
  } ? T[427] : T extends {
84
- 428: any;
90
+ 428: unknown;
85
91
  } ? T[428] : T extends {
86
- 429: any;
92
+ 429: unknown;
87
93
  } ? T[429] : T extends {
88
- 430: any;
94
+ 430: unknown;
89
95
  } ? T[430] : T extends {
90
- 431: any;
96
+ 431: unknown;
91
97
  } ? T[431] : T extends {
92
- 444: any;
98
+ 444: unknown;
93
99
  } ? T[444] : T extends {
94
- 450: any;
100
+ 450: unknown;
95
101
  } ? T[450] : T extends {
96
- 451: any;
102
+ 451: unknown;
97
103
  } ? T[451] : T extends {
98
- 497: any;
104
+ 497: unknown;
99
105
  } ? T[497] : T extends {
100
- 498: any;
106
+ 498: unknown;
101
107
  } ? T[498] : T extends {
102
- 499: any;
108
+ 499: unknown;
103
109
  } ? T[499] : T extends {
104
- "4XX": any;
110
+ "4XX": unknown;
105
111
  } ? T["4XX"] : T extends {
106
- default: any;
112
+ default: unknown;
107
113
  } ? T["default"] : never;
114
+ /** The paths that have each of the methods: upstream's `PathsWithMethod`. */
108
115
  type PathsWithEveryMethod<Paths extends {}, PathnameMethod extends HttpMethod> = {
109
116
  [Pathname in keyof Paths]: Paths[Pathname] extends {
110
- [K in PathnameMethod]: any;
117
+ [K in PathnameMethod]: unknown;
111
118
  } ? Pathname : never;
112
119
  }[keyof Paths];
120
+ /** The paths that have at least one method. */
113
121
  type PathsWithAnyMethod<Paths extends {}> = {
114
122
  [Pathname in keyof Paths]: {
115
123
  [Method in HttpMethod]: Paths[Pathname] extends {
116
- [K in Method]: any;
124
+ [K in Method]: unknown;
117
125
  } ? Pathname : never;
118
126
  }[HttpMethod];
119
127
  }[keyof Paths];
128
+ /**
129
+ * Given an OpenAPI **Paths Object**, find all paths that have the given method. For a union of
130
+ * methods, the paths that have each of them, so a call with either method finds its operation.
131
+ * For `HttpMethod` itself, a method not known yet, the paths that have any method too: TypeScript
132
+ * uses it where a hook's `Method` is not inferred, as in `Parameters<typeof $api.queryOptions>`,
133
+ * and the paths with every method were none (upstream #2178).
134
+ *
135
+ * A union with upstream's type, not a conditional type over the method: code that is generic in
136
+ * the method (`Path extends PathsWithMethod<Paths, Method>`, as swr-openapi has) must still
137
+ * relate one `PathsWithMethod` to another, and TypeScript cannot relate a type to a conditional
138
+ * type that waits for its method (TS2344). For a known method the second member is `never`.
139
+ */
120
140
  type PathsWithMethod<Paths extends {}, PathnameMethod extends HttpMethod> = PathsWithEveryMethod<Paths, PathnameMethod> | (HttpMethod extends PathnameMethod ? PathsWithAnyMethod<Paths> : never);
141
+ /**
142
+ * DO NOT USE!
143
+ * Only used only for OperationObject type inference
144
+ */
121
145
  interface OperationObject {
122
146
  parameters: any;
123
147
  requestBody: any;
124
148
  responses: any;
125
149
  }
150
+ /** Internal helper used in PathsWithMethod */
126
151
  type PathItemObject = {
127
152
  [M in HttpMethod]: OperationObject;
128
153
  } & {
129
154
  parameters?: any;
130
155
  };
156
+ /** Return `responses` for an Operation Object */
131
157
  type ResponseObjectMap<T> = T extends {
132
158
  responses: any;
133
159
  } ? T["responses"] : unknown;
160
+ /** Return `content` for a Response Object */
134
161
  type ResponseContent<T> = T extends {
135
162
  content: any;
136
163
  } ? T["content"] : unknown;
164
+ /** Return type of `requestBody` for an Operation Object */
137
165
  type OperationRequestBody<T> = "requestBody" extends keyof T ? T["requestBody"] : never;
166
+ /** Internal helper to get object type with only the `requestBody` property */
138
167
  type PickRequestBody<T> = "requestBody" extends keyof T ? Pick<T, "requestBody"> : never;
168
+ /** Resolve to `true` if request body is optional, else `false` */
139
169
  type IsOperationRequestBodyOptional<T> = RequiredKeysOf<PickRequestBody<T>> extends never ? true : false;
170
+ /** Internal helper used in OperationRequestBodyContent */
140
171
  type OperationRequestBodyMediaContent<T> = IsOperationRequestBodyOptional<T> extends true ? ResponseContent<NonNullable<OperationRequestBody<T>>> | undefined : ResponseContent<OperationRequestBody<T>>;
172
+ /** Return first `content` from a Request Object Mapping, allowing any media type */
141
173
  type OperationRequestBodyContent<T> = FilterKeys<OperationRequestBodyMediaContent<T>, MediaType> extends never ? FilterKeys<NonNullable<OperationRequestBodyMediaContent<T>>, MediaType> | undefined : FilterKeys<OperationRequestBodyMediaContent<T>, MediaType>;
174
+ /**
175
+ * The statuses of success responses in a Response Object Map: the 2XX statuses, or `default` when
176
+ * no 2XX status is declared. `default` covers every status the operation does not declare (OpenAPI
177
+ * Responses Object), so then it covers every success (upstream #1862). With a 2XX status declared,
178
+ * `default` is left to the errors, as before.
179
+ */
142
180
  type SuccessStatus<T> = [Extract<keyof T, OkStatus>] extends [never] ? "default" : OkStatus;
181
+ /** Return all 2XX responses from a Response Object Map, or `default` if it declares no 2XX one */
143
182
  type SuccessResponse<T extends Record<string | number, any>, Media extends MediaType = MediaType> = GetResponseContent<T, Media, SuccessStatus<T>>;
144
183
  type GetResponseContent<T extends Record<string | number, any>, Media extends MediaType = MediaType, ResponseCode extends keyof T = keyof T> = ResponseCode extends keyof T ? {
145
184
  [K in ResponseCode]: T[K]["content"] extends Record<string, any> ? FilterKeys<T[K]["content"], Media> extends never ? T[K]["content"] : FilterKeys<T[K]["content"], Media> : K extends keyof T ? T[K]["content"] : never;
146
185
  }[ResponseCode] : never;
186
+ /**
187
+ * Return all 5XX and 4XX responses (in that order) from a Response Object Map
188
+ */
147
189
  type ErrorResponse<T extends Record<string | number, any>, Media extends MediaType = MediaType> = GetResponseContent<T, Media, ErrorStatus>;
190
+ /** Return first JSON-like 2XX response from a path + HTTP method */
148
191
  type SuccessResponseJSON<PathMethod extends Record<string | number, any>> = SuccessResponse<ResponseObjectMap<PathMethod>, `${string}/json`>;
192
+ /** Return first JSON-like 5XX or 4XX response from a path + HTTP method */
149
193
  type ErrorResponseJSON<PathMethod extends Record<string | number, any>> = ErrorResponse<ResponseObjectMap<PathMethod>, `${string}/json`>;
194
+ /** Return JSON-like request body from a path + HTTP method */
150
195
  type RequestBodyJSON<PathMethod> = JSONLike<FilterKeys<OperationRequestBody<PathMethod>, "content">>;
196
+ /** Find first match of multiple keys */
151
197
  type FilterKeys<Obj, Matchers> = Obj[keyof Obj & Matchers];
152
- type GetValueWithDefault<Obj, KeyPattern, Default> = Obj extends any ? FilterKeys<Obj, KeyPattern> extends never ? Default : FilterKeys<Obj, KeyPattern> : never;
198
+ /**
199
+ * @deprecated Use `FilterKeys` instead
200
+ * Get the type of a value of an input object with a given key. If the key is
201
+ * not found, return a default type. Works with unions of objects too.
202
+ */
203
+ type GetValueWithDefault<Obj, KeyPattern, Default> = Obj extends unknown ? FilterKeys<Obj, KeyPattern> extends never ? Default : FilterKeys<Obj, KeyPattern> : never;
204
+ /**
205
+ * Return any `[string]/[string]` media type (important because openapi-typesafe-fetch allows any
206
+ * content response, not just JSON-like)
207
+ */
153
208
  type MediaType = `${string}/${string}`;
209
+ /**
210
+ * Return any media type containing "json" (works for "application/json",
211
+ * "application/vnd.api+json", "application/vnd.oai.openapi+json")
212
+ */
154
213
  type JSONLike<T> = FilterKeys<T, `${string}/json`>;
214
+ /**
215
+ * Filter objects that have required keys
216
+ * @deprecated Use `RequiredKeysOf` instead
217
+ */
155
218
  type FindRequiredKeys<T, K extends keyof T> = K extends unknown ? undefined extends T[K] ? never : K : K;
219
+ /**
220
+ * Does this object contain required keys?
221
+ * @deprecated Use `RequiredKeysOf` instead
222
+ */
156
223
  type HasRequiredKeys<T> = FindRequiredKeys<T, keyof T>;
224
+ /**
225
+ * Helper to get the required keys of an object. If no keys are required, will be `undefined` with
226
+ * strictNullChecks enabled, else `never`
227
+ */
157
228
  type RequiredKeysOfHelper<T> = {
158
229
  [K in keyof T]: {} extends Pick<T, K> ? never : K;
159
230
  }[keyof T];
231
+ /** Get the required keys of an object, or `never` if no keys are required */
160
232
  type RequiredKeysOf<T> = RequiredKeysOfHelper<T> extends undefined ? never : RequiredKeysOfHelper<T>;
233
+ /** Marker type for readOnly properties (excluded from request bodies) */
161
234
  type $Read<T> = {
162
235
  readonly $read: T;
163
236
  };
237
+ /** Marker type for writeOnly properties (excluded from response bodies) */
164
238
  type $Write<T> = {
165
239
  readonly $write: T;
166
240
  };
241
+ /** Primitives, also branded ones (`string & { __brand: "Id" }`), which stay unmapped (#2765). */
167
242
  type ReadWritePrimitive = string | number | boolean | bigint | symbol | null | undefined;
243
+ /**
244
+ * Types that stay unmapped. Mapping a function type drops its call signatures, so a `Blob` from
245
+ * `--binary-as-blob` lost its methods (`arrayBuffer()`, `text()`, ...) in response data.
246
+ */
168
247
  type ReadWriteLeaf = ReadWritePrimitive | ((...args: never) => unknown);
248
+ /**
249
+ * Keys of `T` whose value is a `Marker`. A key whose value is only `null` or `undefined` is not
250
+ * marked: `NonNullable` of it is `never`, and `never` extends every marker (upstream #2717). The
251
+ * checks are not distributive (`NonNullable<T[K]>` is not a type parameter), so `never` is seen.
252
+ */
169
253
  type ReadWriteMarkedKeys<T, Marker> = {
170
254
  [K in keyof T]-?: NonNullable<T[K]> extends never ? never : NonNullable<T[K]> extends Marker ? K : never;
171
255
  }[keyof T];
256
+ /**
257
+ * Resolve an array or a tuple element by element. An array uses `T[number]`, not `infer E`: for an
258
+ * intersection of arrays (`allOf`) inference keeps one member and narrowing breaks (upstream
259
+ * #2620). `T` is a plain array when an array of its elements is assignable to it; otherwise it is a
260
+ * tuple (also `[A, ...B[]]`), mapped homomorphically to stay a tuple (upstream #2632). Both keep
261
+ * `readonly` (upstream #2615).
262
+ */
172
263
  type ReadWriteResolveArray<T extends readonly unknown[], Resolved extends "read" | "write"> = T[number][] extends T ? T extends unknown[] ? ReadWriteResolve<T[number], Resolved>[] : readonly ReadWriteResolve<T[number], Resolved>[] : {
173
264
  [K in keyof T]: ReadWriteResolve<T[K], Resolved>;
174
265
  };
175
266
  type ReadWriteResolve<T, Resolved extends "read" | "write"> = Resolved extends "read" ? Readable<T> : Writable<T>;
267
+ /**
268
+ * Resolve type for reading (responses): strips $Write properties, unwraps $Read
269
+ * - $Read<T> → T (readable), continues recursion
270
+ * - $Write<T> → never (excluded from response)
271
+ * - primitives (also branded), functions, arrays and tuples keep their shape; objects resolve
272
+ * recursively
273
+ */
176
274
  type Readable<T> = T extends $Write<any> ? never : T extends $Read<infer U> ? Readable<U> : T extends ReadWriteLeaf ? T : T extends readonly unknown[] ? ReadWriteResolveArray<T, "read"> : T extends object ? {
177
275
  [K in keyof T as K extends ReadWriteMarkedKeys<T, $Write<any>> ? never : K]: Readable<T[K]>;
178
276
  } : T;
277
+ /**
278
+ * Resolve type for writing (requests): strips $Read properties, unwraps $Write
279
+ * - $Write<T> → T (writable), continues recursion
280
+ * - $Read<T> → never (excluded from request)
281
+ * - primitives (also branded), functions, arrays and tuples keep their shape; objects resolve
282
+ * recursively
283
+ */
179
284
  type Writable<T> = T extends $Read<any> ? never : T extends $Write<infer U> ? Writable<U> : T extends ReadWriteLeaf ? T : T extends readonly unknown[] ? ReadWriteResolveArray<T, "write"> : T extends object ? {
180
285
  [K in keyof T as K extends ReadWriteMarkedKeys<T, $Read<any>> ? never : K]: Writable<T[K]>;
181
286
  } & {
package/dist/index.d.mts CHANGED
@@ -1,181 +1,286 @@
1
- type HttpMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace" | "query";
1
+ type HttpMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"
2
+ /** OpenAPI 3.2: a safe, idempotent request with a body. */
3
+ | "query";
4
+ /** 2XX statuses */
2
5
  type OkStatus = 200 | 201 | 202 | 203 | 204 | 206 | 207 | "2XX";
6
+ /** 4XX and 5XX statuses */
3
7
  type ErrorStatus = 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 | "5XX" | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 444 | 450 | 451 | 497 | 498 | 499 | "4XX" | "default";
8
+ /** Get a union of OK Statuses */
4
9
  type OKStatusUnion<T> = FilterKeys<T, OkStatus>;
10
+ /** Get first error status, in order */
5
11
  type FirstErrorStatus<T> = T extends {
6
- 500: any;
12
+ 500: unknown;
7
13
  } ? T[500] : T extends {
8
- 501: any;
14
+ 501: unknown;
9
15
  } ? T[501] : T extends {
10
- 502: any;
16
+ 502: unknown;
11
17
  } ? T[502] : T extends {
12
- 503: any;
18
+ 503: unknown;
13
19
  } ? T[503] : T extends {
14
- 504: any;
20
+ 504: unknown;
15
21
  } ? T[504] : T extends {
16
- 505: any;
22
+ 505: unknown;
17
23
  } ? T[505] : T extends {
18
- 506: any;
24
+ 506: unknown;
19
25
  } ? T[506] : T extends {
20
- 507: any;
26
+ 507: unknown;
21
27
  } ? T[507] : T extends {
22
- 508: any;
28
+ 508: unknown;
23
29
  } ? T[508] : T extends {
24
- 510: any;
30
+ 510: unknown;
25
31
  } ? T[510] : T extends {
26
- 511: any;
32
+ 511: unknown;
27
33
  } ? T[511] : T extends {
28
- "5XX": any;
34
+ "5XX": unknown;
29
35
  } ? T["5XX"] : T extends {
30
- 400: any;
36
+ 400: unknown;
31
37
  } ? T[400] : T extends {
32
- 401: any;
38
+ 401: unknown;
33
39
  } ? T[401] : T extends {
34
- 402: any;
40
+ 402: unknown;
35
41
  } ? T[402] : T extends {
36
- 403: any;
42
+ 403: unknown;
37
43
  } ? T[403] : T extends {
38
- 404: any;
44
+ 404: unknown;
39
45
  } ? T[404] : T extends {
40
- 405: any;
46
+ 405: unknown;
41
47
  } ? T[405] : T extends {
42
- 406: any;
48
+ 406: unknown;
43
49
  } ? T[406] : T extends {
44
- 407: any;
50
+ 407: unknown;
45
51
  } ? T[407] : T extends {
46
- 408: any;
52
+ 408: unknown;
47
53
  } ? T[408] : T extends {
48
- 409: any;
54
+ 409: unknown;
49
55
  } ? T[409] : T extends {
50
- 410: any;
56
+ 410: unknown;
51
57
  } ? T[410] : T extends {
52
- 411: any;
58
+ 411: unknown;
53
59
  } ? T[411] : T extends {
54
- 412: any;
60
+ 412: unknown;
55
61
  } ? T[412] : T extends {
56
- 413: any;
62
+ 413: unknown;
57
63
  } ? T[413] : T extends {
58
- 414: any;
64
+ 414: unknown;
59
65
  } ? T[414] : T extends {
60
- 415: any;
66
+ 415: unknown;
61
67
  } ? T[415] : T extends {
62
- 416: any;
68
+ 416: unknown;
63
69
  } ? T[416] : T extends {
64
- 417: any;
70
+ 417: unknown;
65
71
  } ? T[417] : T extends {
66
- 418: any;
72
+ 418: unknown;
67
73
  } ? T[418] : T extends {
68
- 420: any;
74
+ 420: unknown;
69
75
  } ? T[420] : T extends {
70
- 421: any;
76
+ 421: unknown;
71
77
  } ? T[421] : T extends {
72
- 422: any;
78
+ 422: unknown;
73
79
  } ? T[422] : T extends {
74
- 423: any;
80
+ 423: unknown;
75
81
  } ? T[423] : T extends {
76
- 424: any;
82
+ 424: unknown;
77
83
  } ? T[424] : T extends {
78
- 425: any;
84
+ 425: unknown;
79
85
  } ? T[425] : T extends {
80
- 426: any;
86
+ 426: unknown;
81
87
  } ? T[426] : T extends {
82
- 427: any;
88
+ 427: unknown;
83
89
  } ? T[427] : T extends {
84
- 428: any;
90
+ 428: unknown;
85
91
  } ? T[428] : T extends {
86
- 429: any;
92
+ 429: unknown;
87
93
  } ? T[429] : T extends {
88
- 430: any;
94
+ 430: unknown;
89
95
  } ? T[430] : T extends {
90
- 431: any;
96
+ 431: unknown;
91
97
  } ? T[431] : T extends {
92
- 444: any;
98
+ 444: unknown;
93
99
  } ? T[444] : T extends {
94
- 450: any;
100
+ 450: unknown;
95
101
  } ? T[450] : T extends {
96
- 451: any;
102
+ 451: unknown;
97
103
  } ? T[451] : T extends {
98
- 497: any;
104
+ 497: unknown;
99
105
  } ? T[497] : T extends {
100
- 498: any;
106
+ 498: unknown;
101
107
  } ? T[498] : T extends {
102
- 499: any;
108
+ 499: unknown;
103
109
  } ? T[499] : T extends {
104
- "4XX": any;
110
+ "4XX": unknown;
105
111
  } ? T["4XX"] : T extends {
106
- default: any;
112
+ default: unknown;
107
113
  } ? T["default"] : never;
114
+ /** The paths that have each of the methods: upstream's `PathsWithMethod`. */
108
115
  type PathsWithEveryMethod<Paths extends {}, PathnameMethod extends HttpMethod> = {
109
116
  [Pathname in keyof Paths]: Paths[Pathname] extends {
110
- [K in PathnameMethod]: any;
117
+ [K in PathnameMethod]: unknown;
111
118
  } ? Pathname : never;
112
119
  }[keyof Paths];
120
+ /** The paths that have at least one method. */
113
121
  type PathsWithAnyMethod<Paths extends {}> = {
114
122
  [Pathname in keyof Paths]: {
115
123
  [Method in HttpMethod]: Paths[Pathname] extends {
116
- [K in Method]: any;
124
+ [K in Method]: unknown;
117
125
  } ? Pathname : never;
118
126
  }[HttpMethod];
119
127
  }[keyof Paths];
128
+ /**
129
+ * Given an OpenAPI **Paths Object**, find all paths that have the given method. For a union of
130
+ * methods, the paths that have each of them, so a call with either method finds its operation.
131
+ * For `HttpMethod` itself, a method not known yet, the paths that have any method too: TypeScript
132
+ * uses it where a hook's `Method` is not inferred, as in `Parameters<typeof $api.queryOptions>`,
133
+ * and the paths with every method were none (upstream #2178).
134
+ *
135
+ * A union with upstream's type, not a conditional type over the method: code that is generic in
136
+ * the method (`Path extends PathsWithMethod<Paths, Method>`, as swr-openapi has) must still
137
+ * relate one `PathsWithMethod` to another, and TypeScript cannot relate a type to a conditional
138
+ * type that waits for its method (TS2344). For a known method the second member is `never`.
139
+ */
120
140
  type PathsWithMethod<Paths extends {}, PathnameMethod extends HttpMethod> = PathsWithEveryMethod<Paths, PathnameMethod> | (HttpMethod extends PathnameMethod ? PathsWithAnyMethod<Paths> : never);
141
+ /**
142
+ * DO NOT USE!
143
+ * Only used only for OperationObject type inference
144
+ */
121
145
  interface OperationObject {
122
146
  parameters: any;
123
147
  requestBody: any;
124
148
  responses: any;
125
149
  }
150
+ /** Internal helper used in PathsWithMethod */
126
151
  type PathItemObject = {
127
152
  [M in HttpMethod]: OperationObject;
128
153
  } & {
129
154
  parameters?: any;
130
155
  };
156
+ /** Return `responses` for an Operation Object */
131
157
  type ResponseObjectMap<T> = T extends {
132
158
  responses: any;
133
159
  } ? T["responses"] : unknown;
160
+ /** Return `content` for a Response Object */
134
161
  type ResponseContent<T> = T extends {
135
162
  content: any;
136
163
  } ? T["content"] : unknown;
164
+ /** Return type of `requestBody` for an Operation Object */
137
165
  type OperationRequestBody<T> = "requestBody" extends keyof T ? T["requestBody"] : never;
166
+ /** Internal helper to get object type with only the `requestBody` property */
138
167
  type PickRequestBody<T> = "requestBody" extends keyof T ? Pick<T, "requestBody"> : never;
168
+ /** Resolve to `true` if request body is optional, else `false` */
139
169
  type IsOperationRequestBodyOptional<T> = RequiredKeysOf<PickRequestBody<T>> extends never ? true : false;
170
+ /** Internal helper used in OperationRequestBodyContent */
140
171
  type OperationRequestBodyMediaContent<T> = IsOperationRequestBodyOptional<T> extends true ? ResponseContent<NonNullable<OperationRequestBody<T>>> | undefined : ResponseContent<OperationRequestBody<T>>;
172
+ /** Return first `content` from a Request Object Mapping, allowing any media type */
141
173
  type OperationRequestBodyContent<T> = FilterKeys<OperationRequestBodyMediaContent<T>, MediaType> extends never ? FilterKeys<NonNullable<OperationRequestBodyMediaContent<T>>, MediaType> | undefined : FilterKeys<OperationRequestBodyMediaContent<T>, MediaType>;
174
+ /**
175
+ * The statuses of success responses in a Response Object Map: the 2XX statuses, or `default` when
176
+ * no 2XX status is declared. `default` covers every status the operation does not declare (OpenAPI
177
+ * Responses Object), so then it covers every success (upstream #1862). With a 2XX status declared,
178
+ * `default` is left to the errors, as before.
179
+ */
142
180
  type SuccessStatus<T> = [Extract<keyof T, OkStatus>] extends [never] ? "default" : OkStatus;
181
+ /** Return all 2XX responses from a Response Object Map, or `default` if it declares no 2XX one */
143
182
  type SuccessResponse<T extends Record<string | number, any>, Media extends MediaType = MediaType> = GetResponseContent<T, Media, SuccessStatus<T>>;
144
183
  type GetResponseContent<T extends Record<string | number, any>, Media extends MediaType = MediaType, ResponseCode extends keyof T = keyof T> = ResponseCode extends keyof T ? {
145
184
  [K in ResponseCode]: T[K]["content"] extends Record<string, any> ? FilterKeys<T[K]["content"], Media> extends never ? T[K]["content"] : FilterKeys<T[K]["content"], Media> : K extends keyof T ? T[K]["content"] : never;
146
185
  }[ResponseCode] : never;
186
+ /**
187
+ * Return all 5XX and 4XX responses (in that order) from a Response Object Map
188
+ */
147
189
  type ErrorResponse<T extends Record<string | number, any>, Media extends MediaType = MediaType> = GetResponseContent<T, Media, ErrorStatus>;
190
+ /** Return first JSON-like 2XX response from a path + HTTP method */
148
191
  type SuccessResponseJSON<PathMethod extends Record<string | number, any>> = SuccessResponse<ResponseObjectMap<PathMethod>, `${string}/json`>;
192
+ /** Return first JSON-like 5XX or 4XX response from a path + HTTP method */
149
193
  type ErrorResponseJSON<PathMethod extends Record<string | number, any>> = ErrorResponse<ResponseObjectMap<PathMethod>, `${string}/json`>;
194
+ /** Return JSON-like request body from a path + HTTP method */
150
195
  type RequestBodyJSON<PathMethod> = JSONLike<FilterKeys<OperationRequestBody<PathMethod>, "content">>;
196
+ /** Find first match of multiple keys */
151
197
  type FilterKeys<Obj, Matchers> = Obj[keyof Obj & Matchers];
152
- type GetValueWithDefault<Obj, KeyPattern, Default> = Obj extends any ? FilterKeys<Obj, KeyPattern> extends never ? Default : FilterKeys<Obj, KeyPattern> : never;
198
+ /**
199
+ * @deprecated Use `FilterKeys` instead
200
+ * Get the type of a value of an input object with a given key. If the key is
201
+ * not found, return a default type. Works with unions of objects too.
202
+ */
203
+ type GetValueWithDefault<Obj, KeyPattern, Default> = Obj extends unknown ? FilterKeys<Obj, KeyPattern> extends never ? Default : FilterKeys<Obj, KeyPattern> : never;
204
+ /**
205
+ * Return any `[string]/[string]` media type (important because openapi-typesafe-fetch allows any
206
+ * content response, not just JSON-like)
207
+ */
153
208
  type MediaType = `${string}/${string}`;
209
+ /**
210
+ * Return any media type containing "json" (works for "application/json",
211
+ * "application/vnd.api+json", "application/vnd.oai.openapi+json")
212
+ */
154
213
  type JSONLike<T> = FilterKeys<T, `${string}/json`>;
214
+ /**
215
+ * Filter objects that have required keys
216
+ * @deprecated Use `RequiredKeysOf` instead
217
+ */
155
218
  type FindRequiredKeys<T, K extends keyof T> = K extends unknown ? undefined extends T[K] ? never : K : K;
219
+ /**
220
+ * Does this object contain required keys?
221
+ * @deprecated Use `RequiredKeysOf` instead
222
+ */
156
223
  type HasRequiredKeys<T> = FindRequiredKeys<T, keyof T>;
224
+ /**
225
+ * Helper to get the required keys of an object. If no keys are required, will be `undefined` with
226
+ * strictNullChecks enabled, else `never`
227
+ */
157
228
  type RequiredKeysOfHelper<T> = {
158
229
  [K in keyof T]: {} extends Pick<T, K> ? never : K;
159
230
  }[keyof T];
231
+ /** Get the required keys of an object, or `never` if no keys are required */
160
232
  type RequiredKeysOf<T> = RequiredKeysOfHelper<T> extends undefined ? never : RequiredKeysOfHelper<T>;
233
+ /** Marker type for readOnly properties (excluded from request bodies) */
161
234
  type $Read<T> = {
162
235
  readonly $read: T;
163
236
  };
237
+ /** Marker type for writeOnly properties (excluded from response bodies) */
164
238
  type $Write<T> = {
165
239
  readonly $write: T;
166
240
  };
241
+ /** Primitives, also branded ones (`string & { __brand: "Id" }`), which stay unmapped (#2765). */
167
242
  type ReadWritePrimitive = string | number | boolean | bigint | symbol | null | undefined;
243
+ /**
244
+ * Types that stay unmapped. Mapping a function type drops its call signatures, so a `Blob` from
245
+ * `--binary-as-blob` lost its methods (`arrayBuffer()`, `text()`, ...) in response data.
246
+ */
168
247
  type ReadWriteLeaf = ReadWritePrimitive | ((...args: never) => unknown);
248
+ /**
249
+ * Keys of `T` whose value is a `Marker`. A key whose value is only `null` or `undefined` is not
250
+ * marked: `NonNullable` of it is `never`, and `never` extends every marker (upstream #2717). The
251
+ * checks are not distributive (`NonNullable<T[K]>` is not a type parameter), so `never` is seen.
252
+ */
169
253
  type ReadWriteMarkedKeys<T, Marker> = {
170
254
  [K in keyof T]-?: NonNullable<T[K]> extends never ? never : NonNullable<T[K]> extends Marker ? K : never;
171
255
  }[keyof T];
256
+ /**
257
+ * Resolve an array or a tuple element by element. An array uses `T[number]`, not `infer E`: for an
258
+ * intersection of arrays (`allOf`) inference keeps one member and narrowing breaks (upstream
259
+ * #2620). `T` is a plain array when an array of its elements is assignable to it; otherwise it is a
260
+ * tuple (also `[A, ...B[]]`), mapped homomorphically to stay a tuple (upstream #2632). Both keep
261
+ * `readonly` (upstream #2615).
262
+ */
172
263
  type ReadWriteResolveArray<T extends readonly unknown[], Resolved extends "read" | "write"> = T[number][] extends T ? T extends unknown[] ? ReadWriteResolve<T[number], Resolved>[] : readonly ReadWriteResolve<T[number], Resolved>[] : {
173
264
  [K in keyof T]: ReadWriteResolve<T[K], Resolved>;
174
265
  };
175
266
  type ReadWriteResolve<T, Resolved extends "read" | "write"> = Resolved extends "read" ? Readable<T> : Writable<T>;
267
+ /**
268
+ * Resolve type for reading (responses): strips $Write properties, unwraps $Read
269
+ * - $Read<T> → T (readable), continues recursion
270
+ * - $Write<T> → never (excluded from response)
271
+ * - primitives (also branded), functions, arrays and tuples keep their shape; objects resolve
272
+ * recursively
273
+ */
176
274
  type Readable<T> = T extends $Write<any> ? never : T extends $Read<infer U> ? Readable<U> : T extends ReadWriteLeaf ? T : T extends readonly unknown[] ? ReadWriteResolveArray<T, "read"> : T extends object ? {
177
275
  [K in keyof T as K extends ReadWriteMarkedKeys<T, $Write<any>> ? never : K]: Readable<T[K]>;
178
276
  } : T;
277
+ /**
278
+ * Resolve type for writing (requests): strips $Read properties, unwraps $Write
279
+ * - $Write<T> → T (writable), continues recursion
280
+ * - $Read<T> → never (excluded from request)
281
+ * - primitives (also branded), functions, arrays and tuples keep their shape; objects resolve
282
+ * recursively
283
+ */
179
284
  type Writable<T> = T extends $Read<any> ? never : T extends $Write<infer U> ? Writable<U> : T extends ReadWriteLeaf ? T : T extends readonly unknown[] ? ReadWriteResolveArray<T, "write"> : T extends object ? {
180
285
  [K in keyof T as K extends ReadWriteMarkedKeys<T, $Read<any>> ? never : K]: Writable<T[K]>;
181
286
  } & {
package/dist/index.d.ts CHANGED
@@ -1,181 +1,286 @@
1
- type HttpMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace" | "query";
1
+ type HttpMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"
2
+ /** OpenAPI 3.2: a safe, idempotent request with a body. */
3
+ | "query";
4
+ /** 2XX statuses */
2
5
  type OkStatus = 200 | 201 | 202 | 203 | 204 | 206 | 207 | "2XX";
6
+ /** 4XX and 5XX statuses */
3
7
  type ErrorStatus = 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 | "5XX" | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 444 | 450 | 451 | 497 | 498 | 499 | "4XX" | "default";
8
+ /** Get a union of OK Statuses */
4
9
  type OKStatusUnion<T> = FilterKeys<T, OkStatus>;
10
+ /** Get first error status, in order */
5
11
  type FirstErrorStatus<T> = T extends {
6
- 500: any;
12
+ 500: unknown;
7
13
  } ? T[500] : T extends {
8
- 501: any;
14
+ 501: unknown;
9
15
  } ? T[501] : T extends {
10
- 502: any;
16
+ 502: unknown;
11
17
  } ? T[502] : T extends {
12
- 503: any;
18
+ 503: unknown;
13
19
  } ? T[503] : T extends {
14
- 504: any;
20
+ 504: unknown;
15
21
  } ? T[504] : T extends {
16
- 505: any;
22
+ 505: unknown;
17
23
  } ? T[505] : T extends {
18
- 506: any;
24
+ 506: unknown;
19
25
  } ? T[506] : T extends {
20
- 507: any;
26
+ 507: unknown;
21
27
  } ? T[507] : T extends {
22
- 508: any;
28
+ 508: unknown;
23
29
  } ? T[508] : T extends {
24
- 510: any;
30
+ 510: unknown;
25
31
  } ? T[510] : T extends {
26
- 511: any;
32
+ 511: unknown;
27
33
  } ? T[511] : T extends {
28
- "5XX": any;
34
+ "5XX": unknown;
29
35
  } ? T["5XX"] : T extends {
30
- 400: any;
36
+ 400: unknown;
31
37
  } ? T[400] : T extends {
32
- 401: any;
38
+ 401: unknown;
33
39
  } ? T[401] : T extends {
34
- 402: any;
40
+ 402: unknown;
35
41
  } ? T[402] : T extends {
36
- 403: any;
42
+ 403: unknown;
37
43
  } ? T[403] : T extends {
38
- 404: any;
44
+ 404: unknown;
39
45
  } ? T[404] : T extends {
40
- 405: any;
46
+ 405: unknown;
41
47
  } ? T[405] : T extends {
42
- 406: any;
48
+ 406: unknown;
43
49
  } ? T[406] : T extends {
44
- 407: any;
50
+ 407: unknown;
45
51
  } ? T[407] : T extends {
46
- 408: any;
52
+ 408: unknown;
47
53
  } ? T[408] : T extends {
48
- 409: any;
54
+ 409: unknown;
49
55
  } ? T[409] : T extends {
50
- 410: any;
56
+ 410: unknown;
51
57
  } ? T[410] : T extends {
52
- 411: any;
58
+ 411: unknown;
53
59
  } ? T[411] : T extends {
54
- 412: any;
60
+ 412: unknown;
55
61
  } ? T[412] : T extends {
56
- 413: any;
62
+ 413: unknown;
57
63
  } ? T[413] : T extends {
58
- 414: any;
64
+ 414: unknown;
59
65
  } ? T[414] : T extends {
60
- 415: any;
66
+ 415: unknown;
61
67
  } ? T[415] : T extends {
62
- 416: any;
68
+ 416: unknown;
63
69
  } ? T[416] : T extends {
64
- 417: any;
70
+ 417: unknown;
65
71
  } ? T[417] : T extends {
66
- 418: any;
72
+ 418: unknown;
67
73
  } ? T[418] : T extends {
68
- 420: any;
74
+ 420: unknown;
69
75
  } ? T[420] : T extends {
70
- 421: any;
76
+ 421: unknown;
71
77
  } ? T[421] : T extends {
72
- 422: any;
78
+ 422: unknown;
73
79
  } ? T[422] : T extends {
74
- 423: any;
80
+ 423: unknown;
75
81
  } ? T[423] : T extends {
76
- 424: any;
82
+ 424: unknown;
77
83
  } ? T[424] : T extends {
78
- 425: any;
84
+ 425: unknown;
79
85
  } ? T[425] : T extends {
80
- 426: any;
86
+ 426: unknown;
81
87
  } ? T[426] : T extends {
82
- 427: any;
88
+ 427: unknown;
83
89
  } ? T[427] : T extends {
84
- 428: any;
90
+ 428: unknown;
85
91
  } ? T[428] : T extends {
86
- 429: any;
92
+ 429: unknown;
87
93
  } ? T[429] : T extends {
88
- 430: any;
94
+ 430: unknown;
89
95
  } ? T[430] : T extends {
90
- 431: any;
96
+ 431: unknown;
91
97
  } ? T[431] : T extends {
92
- 444: any;
98
+ 444: unknown;
93
99
  } ? T[444] : T extends {
94
- 450: any;
100
+ 450: unknown;
95
101
  } ? T[450] : T extends {
96
- 451: any;
102
+ 451: unknown;
97
103
  } ? T[451] : T extends {
98
- 497: any;
104
+ 497: unknown;
99
105
  } ? T[497] : T extends {
100
- 498: any;
106
+ 498: unknown;
101
107
  } ? T[498] : T extends {
102
- 499: any;
108
+ 499: unknown;
103
109
  } ? T[499] : T extends {
104
- "4XX": any;
110
+ "4XX": unknown;
105
111
  } ? T["4XX"] : T extends {
106
- default: any;
112
+ default: unknown;
107
113
  } ? T["default"] : never;
114
+ /** The paths that have each of the methods: upstream's `PathsWithMethod`. */
108
115
  type PathsWithEveryMethod<Paths extends {}, PathnameMethod extends HttpMethod> = {
109
116
  [Pathname in keyof Paths]: Paths[Pathname] extends {
110
- [K in PathnameMethod]: any;
117
+ [K in PathnameMethod]: unknown;
111
118
  } ? Pathname : never;
112
119
  }[keyof Paths];
120
+ /** The paths that have at least one method. */
113
121
  type PathsWithAnyMethod<Paths extends {}> = {
114
122
  [Pathname in keyof Paths]: {
115
123
  [Method in HttpMethod]: Paths[Pathname] extends {
116
- [K in Method]: any;
124
+ [K in Method]: unknown;
117
125
  } ? Pathname : never;
118
126
  }[HttpMethod];
119
127
  }[keyof Paths];
128
+ /**
129
+ * Given an OpenAPI **Paths Object**, find all paths that have the given method. For a union of
130
+ * methods, the paths that have each of them, so a call with either method finds its operation.
131
+ * For `HttpMethod` itself, a method not known yet, the paths that have any method too: TypeScript
132
+ * uses it where a hook's `Method` is not inferred, as in `Parameters<typeof $api.queryOptions>`,
133
+ * and the paths with every method were none (upstream #2178).
134
+ *
135
+ * A union with upstream's type, not a conditional type over the method: code that is generic in
136
+ * the method (`Path extends PathsWithMethod<Paths, Method>`, as swr-openapi has) must still
137
+ * relate one `PathsWithMethod` to another, and TypeScript cannot relate a type to a conditional
138
+ * type that waits for its method (TS2344). For a known method the second member is `never`.
139
+ */
120
140
  type PathsWithMethod<Paths extends {}, PathnameMethod extends HttpMethod> = PathsWithEveryMethod<Paths, PathnameMethod> | (HttpMethod extends PathnameMethod ? PathsWithAnyMethod<Paths> : never);
141
+ /**
142
+ * DO NOT USE!
143
+ * Only used only for OperationObject type inference
144
+ */
121
145
  interface OperationObject {
122
146
  parameters: any;
123
147
  requestBody: any;
124
148
  responses: any;
125
149
  }
150
+ /** Internal helper used in PathsWithMethod */
126
151
  type PathItemObject = {
127
152
  [M in HttpMethod]: OperationObject;
128
153
  } & {
129
154
  parameters?: any;
130
155
  };
156
+ /** Return `responses` for an Operation Object */
131
157
  type ResponseObjectMap<T> = T extends {
132
158
  responses: any;
133
159
  } ? T["responses"] : unknown;
160
+ /** Return `content` for a Response Object */
134
161
  type ResponseContent<T> = T extends {
135
162
  content: any;
136
163
  } ? T["content"] : unknown;
164
+ /** Return type of `requestBody` for an Operation Object */
137
165
  type OperationRequestBody<T> = "requestBody" extends keyof T ? T["requestBody"] : never;
166
+ /** Internal helper to get object type with only the `requestBody` property */
138
167
  type PickRequestBody<T> = "requestBody" extends keyof T ? Pick<T, "requestBody"> : never;
168
+ /** Resolve to `true` if request body is optional, else `false` */
139
169
  type IsOperationRequestBodyOptional<T> = RequiredKeysOf<PickRequestBody<T>> extends never ? true : false;
170
+ /** Internal helper used in OperationRequestBodyContent */
140
171
  type OperationRequestBodyMediaContent<T> = IsOperationRequestBodyOptional<T> extends true ? ResponseContent<NonNullable<OperationRequestBody<T>>> | undefined : ResponseContent<OperationRequestBody<T>>;
172
+ /** Return first `content` from a Request Object Mapping, allowing any media type */
141
173
  type OperationRequestBodyContent<T> = FilterKeys<OperationRequestBodyMediaContent<T>, MediaType> extends never ? FilterKeys<NonNullable<OperationRequestBodyMediaContent<T>>, MediaType> | undefined : FilterKeys<OperationRequestBodyMediaContent<T>, MediaType>;
174
+ /**
175
+ * The statuses of success responses in a Response Object Map: the 2XX statuses, or `default` when
176
+ * no 2XX status is declared. `default` covers every status the operation does not declare (OpenAPI
177
+ * Responses Object), so then it covers every success (upstream #1862). With a 2XX status declared,
178
+ * `default` is left to the errors, as before.
179
+ */
142
180
  type SuccessStatus<T> = [Extract<keyof T, OkStatus>] extends [never] ? "default" : OkStatus;
181
+ /** Return all 2XX responses from a Response Object Map, or `default` if it declares no 2XX one */
143
182
  type SuccessResponse<T extends Record<string | number, any>, Media extends MediaType = MediaType> = GetResponseContent<T, Media, SuccessStatus<T>>;
144
183
  type GetResponseContent<T extends Record<string | number, any>, Media extends MediaType = MediaType, ResponseCode extends keyof T = keyof T> = ResponseCode extends keyof T ? {
145
184
  [K in ResponseCode]: T[K]["content"] extends Record<string, any> ? FilterKeys<T[K]["content"], Media> extends never ? T[K]["content"] : FilterKeys<T[K]["content"], Media> : K extends keyof T ? T[K]["content"] : never;
146
185
  }[ResponseCode] : never;
186
+ /**
187
+ * Return all 5XX and 4XX responses (in that order) from a Response Object Map
188
+ */
147
189
  type ErrorResponse<T extends Record<string | number, any>, Media extends MediaType = MediaType> = GetResponseContent<T, Media, ErrorStatus>;
190
+ /** Return first JSON-like 2XX response from a path + HTTP method */
148
191
  type SuccessResponseJSON<PathMethod extends Record<string | number, any>> = SuccessResponse<ResponseObjectMap<PathMethod>, `${string}/json`>;
192
+ /** Return first JSON-like 5XX or 4XX response from a path + HTTP method */
149
193
  type ErrorResponseJSON<PathMethod extends Record<string | number, any>> = ErrorResponse<ResponseObjectMap<PathMethod>, `${string}/json`>;
194
+ /** Return JSON-like request body from a path + HTTP method */
150
195
  type RequestBodyJSON<PathMethod> = JSONLike<FilterKeys<OperationRequestBody<PathMethod>, "content">>;
196
+ /** Find first match of multiple keys */
151
197
  type FilterKeys<Obj, Matchers> = Obj[keyof Obj & Matchers];
152
- type GetValueWithDefault<Obj, KeyPattern, Default> = Obj extends any ? FilterKeys<Obj, KeyPattern> extends never ? Default : FilterKeys<Obj, KeyPattern> : never;
198
+ /**
199
+ * @deprecated Use `FilterKeys` instead
200
+ * Get the type of a value of an input object with a given key. If the key is
201
+ * not found, return a default type. Works with unions of objects too.
202
+ */
203
+ type GetValueWithDefault<Obj, KeyPattern, Default> = Obj extends unknown ? FilterKeys<Obj, KeyPattern> extends never ? Default : FilterKeys<Obj, KeyPattern> : never;
204
+ /**
205
+ * Return any `[string]/[string]` media type (important because openapi-typesafe-fetch allows any
206
+ * content response, not just JSON-like)
207
+ */
153
208
  type MediaType = `${string}/${string}`;
209
+ /**
210
+ * Return any media type containing "json" (works for "application/json",
211
+ * "application/vnd.api+json", "application/vnd.oai.openapi+json")
212
+ */
154
213
  type JSONLike<T> = FilterKeys<T, `${string}/json`>;
214
+ /**
215
+ * Filter objects that have required keys
216
+ * @deprecated Use `RequiredKeysOf` instead
217
+ */
155
218
  type FindRequiredKeys<T, K extends keyof T> = K extends unknown ? undefined extends T[K] ? never : K : K;
219
+ /**
220
+ * Does this object contain required keys?
221
+ * @deprecated Use `RequiredKeysOf` instead
222
+ */
156
223
  type HasRequiredKeys<T> = FindRequiredKeys<T, keyof T>;
224
+ /**
225
+ * Helper to get the required keys of an object. If no keys are required, will be `undefined` with
226
+ * strictNullChecks enabled, else `never`
227
+ */
157
228
  type RequiredKeysOfHelper<T> = {
158
229
  [K in keyof T]: {} extends Pick<T, K> ? never : K;
159
230
  }[keyof T];
231
+ /** Get the required keys of an object, or `never` if no keys are required */
160
232
  type RequiredKeysOf<T> = RequiredKeysOfHelper<T> extends undefined ? never : RequiredKeysOfHelper<T>;
233
+ /** Marker type for readOnly properties (excluded from request bodies) */
161
234
  type $Read<T> = {
162
235
  readonly $read: T;
163
236
  };
237
+ /** Marker type for writeOnly properties (excluded from response bodies) */
164
238
  type $Write<T> = {
165
239
  readonly $write: T;
166
240
  };
241
+ /** Primitives, also branded ones (`string & { __brand: "Id" }`), which stay unmapped (#2765). */
167
242
  type ReadWritePrimitive = string | number | boolean | bigint | symbol | null | undefined;
243
+ /**
244
+ * Types that stay unmapped. Mapping a function type drops its call signatures, so a `Blob` from
245
+ * `--binary-as-blob` lost its methods (`arrayBuffer()`, `text()`, ...) in response data.
246
+ */
168
247
  type ReadWriteLeaf = ReadWritePrimitive | ((...args: never) => unknown);
248
+ /**
249
+ * Keys of `T` whose value is a `Marker`. A key whose value is only `null` or `undefined` is not
250
+ * marked: `NonNullable` of it is `never`, and `never` extends every marker (upstream #2717). The
251
+ * checks are not distributive (`NonNullable<T[K]>` is not a type parameter), so `never` is seen.
252
+ */
169
253
  type ReadWriteMarkedKeys<T, Marker> = {
170
254
  [K in keyof T]-?: NonNullable<T[K]> extends never ? never : NonNullable<T[K]> extends Marker ? K : never;
171
255
  }[keyof T];
256
+ /**
257
+ * Resolve an array or a tuple element by element. An array uses `T[number]`, not `infer E`: for an
258
+ * intersection of arrays (`allOf`) inference keeps one member and narrowing breaks (upstream
259
+ * #2620). `T` is a plain array when an array of its elements is assignable to it; otherwise it is a
260
+ * tuple (also `[A, ...B[]]`), mapped homomorphically to stay a tuple (upstream #2632). Both keep
261
+ * `readonly` (upstream #2615).
262
+ */
172
263
  type ReadWriteResolveArray<T extends readonly unknown[], Resolved extends "read" | "write"> = T[number][] extends T ? T extends unknown[] ? ReadWriteResolve<T[number], Resolved>[] : readonly ReadWriteResolve<T[number], Resolved>[] : {
173
264
  [K in keyof T]: ReadWriteResolve<T[K], Resolved>;
174
265
  };
175
266
  type ReadWriteResolve<T, Resolved extends "read" | "write"> = Resolved extends "read" ? Readable<T> : Writable<T>;
267
+ /**
268
+ * Resolve type for reading (responses): strips $Write properties, unwraps $Read
269
+ * - $Read<T> → T (readable), continues recursion
270
+ * - $Write<T> → never (excluded from response)
271
+ * - primitives (also branded), functions, arrays and tuples keep their shape; objects resolve
272
+ * recursively
273
+ */
176
274
  type Readable<T> = T extends $Write<any> ? never : T extends $Read<infer U> ? Readable<U> : T extends ReadWriteLeaf ? T : T extends readonly unknown[] ? ReadWriteResolveArray<T, "read"> : T extends object ? {
177
275
  [K in keyof T as K extends ReadWriteMarkedKeys<T, $Write<any>> ? never : K]: Readable<T[K]>;
178
276
  } : T;
277
+ /**
278
+ * Resolve type for writing (requests): strips $Read properties, unwraps $Write
279
+ * - $Write<T> → T (writable), continues recursion
280
+ * - $Read<T> → never (excluded from request)
281
+ * - primitives (also branded), functions, arrays and tuples keep their shape; objects resolve
282
+ * recursively
283
+ */
179
284
  type Writable<T> = T extends $Read<any> ? never : T extends $Write<infer U> ? Writable<U> : T extends ReadWriteLeaf ? T : T extends readonly unknown[] ? ReadWriteResolveArray<T, "write"> : T extends object ? {
180
285
  [K in keyof T as K extends ReadWriteMarkedKeys<T, $Read<any>> ? never : K]: Writable<T[K]>;
181
286
  } & {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "openapi-typesafe-helpers",
3
3
  "description": "TypeScript helpers for consuming openapi-typesafe types",
4
- "version": "1.0.0-rc.1",
4
+ "version": "1.0.0-rc.2",
5
5
  "author": {
6
6
  "name": "Fedor Chishchin",
7
7
  "url": "https://github.com/fedorello"
@@ -36,7 +36,8 @@
36
36
  "url": "https://github.com/openapi-typesafe/openapi-typesafe/issues"
37
37
  },
38
38
  "devDependencies": {
39
- "typescript": "^6.0.3"
39
+ "typescript": "^6.0.3",
40
+ "vite-node": "6.0.0"
40
41
  },
41
42
  "engines": {
42
43
  "node": ">=22"
@@ -44,9 +45,10 @@
44
45
  "scripts": {
45
46
  "build": "unbuild",
46
47
  "format": "biome format src --write",
47
- "lint": "pnpm run lint:js && pnpm run lint:ts",
48
+ "lint": "pnpm run lint:js && pnpm run lint:ts && pnpm run lint:sizes",
48
49
  "lint:js": "biome check src",
49
50
  "lint:ts": "tsc --noEmit",
51
+ "lint:sizes": "vite-node ../openapi-typesafe/scripts/size-rules/check-sizes.ts src",
50
52
  "test": "pnpm run test:exports",
51
53
  "test:exports": "pnpm run build && ../../scripts/check-exports.sh"
52
54
  }