@huanglangjian/specs 0.4.0 → 0.6.0
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/dist/index.d.mts +1729 -482
- package/dist/index.mjs +1644 -836
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -11
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,929 @@
|
|
|
1
|
-
//#region ../../node_modules/.pnpm
|
|
1
|
+
//#region ../../node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.ts
|
|
2
|
+
/** The Standard Typed interface. This is a base type extended by other specs. */
|
|
3
|
+
interface StandardTypedV1<Input = unknown, Output = Input> {
|
|
4
|
+
/** The Standard properties. */
|
|
5
|
+
readonly "~standard": StandardTypedV1.Props<Input, Output>;
|
|
6
|
+
}
|
|
7
|
+
declare namespace StandardTypedV1 {
|
|
8
|
+
/** The Standard Typed properties interface. */
|
|
9
|
+
interface Props<Input = unknown, Output = Input> {
|
|
10
|
+
/** The version number of the standard. */
|
|
11
|
+
readonly version: 1;
|
|
12
|
+
/** The vendor name of the schema library. */
|
|
13
|
+
readonly vendor: string;
|
|
14
|
+
/** Inferred types associated with the schema. */
|
|
15
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** The Standard Typed types interface. */
|
|
18
|
+
interface Types<Input = unknown, Output = Input> {
|
|
19
|
+
/** The input type of the schema. */
|
|
20
|
+
readonly input: Input;
|
|
21
|
+
/** The output type of the schema. */
|
|
22
|
+
readonly output: Output;
|
|
23
|
+
}
|
|
24
|
+
/** Infers the input type of a Standard Typed. */
|
|
25
|
+
type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
26
|
+
/** Infers the output type of a Standard Typed. */
|
|
27
|
+
type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
28
|
+
}
|
|
29
|
+
/** The Standard Schema interface. */
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/primitive.d.ts
|
|
32
|
+
/**
|
|
33
|
+
Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
|
34
|
+
|
|
35
|
+
@category Type
|
|
36
|
+
*/
|
|
37
|
+
type Primitive = null | undefined | string | number | boolean | symbol | bigint;
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/is-any.d.ts
|
|
40
|
+
/**
|
|
41
|
+
Returns a boolean for whether the given type is `any`.
|
|
42
|
+
|
|
43
|
+
@link https://stackoverflow.com/a/49928360/1490091
|
|
44
|
+
|
|
45
|
+
Useful in type utilities, such as disallowing `any`s to be passed to a function.
|
|
46
|
+
|
|
47
|
+
@example
|
|
48
|
+
```
|
|
49
|
+
import type {IsAny} from 'type-fest';
|
|
50
|
+
|
|
51
|
+
const typedObject = {a: 1, b: 2} as const;
|
|
52
|
+
const anyObject: any = {a: 1, b: 2};
|
|
53
|
+
|
|
54
|
+
function get<O extends (IsAny<O> extends true ? {} : Record<string, number>), K extends keyof O = keyof O>(object: O, key: K) {
|
|
55
|
+
return object[key];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const typedA = get(typedObject, 'a');
|
|
59
|
+
//=> 1
|
|
60
|
+
|
|
61
|
+
const anyA = get(anyObject, 'a');
|
|
62
|
+
//=> any
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
@category Type Guard
|
|
66
|
+
@category Utilities
|
|
67
|
+
*/
|
|
68
|
+
type IsAny<T> = 0 extends 1 & NoInfer<T> ? true : false;
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/is-optional-key-of.d.ts
|
|
71
|
+
/**
|
|
72
|
+
Returns a boolean for whether the given key is an optional key of type.
|
|
73
|
+
|
|
74
|
+
This is useful when writing utility types or schema validators that need to differentiate `optional` keys.
|
|
75
|
+
|
|
76
|
+
@example
|
|
77
|
+
```
|
|
78
|
+
import type {IsOptionalKeyOf} from 'type-fest';
|
|
79
|
+
|
|
80
|
+
type User = {
|
|
81
|
+
name: string;
|
|
82
|
+
surname: string;
|
|
83
|
+
|
|
84
|
+
luckyNumber?: number;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
type Admin = {
|
|
88
|
+
name: string;
|
|
89
|
+
surname?: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
type T1 = IsOptionalKeyOf<User, 'luckyNumber'>;
|
|
93
|
+
//=> true
|
|
94
|
+
|
|
95
|
+
type T2 = IsOptionalKeyOf<User, 'name'>;
|
|
96
|
+
//=> false
|
|
97
|
+
|
|
98
|
+
type T3 = IsOptionalKeyOf<User, 'name' | 'luckyNumber'>;
|
|
99
|
+
//=> boolean
|
|
100
|
+
|
|
101
|
+
type T4 = IsOptionalKeyOf<User | Admin, 'name'>;
|
|
102
|
+
//=> false
|
|
103
|
+
|
|
104
|
+
type T5 = IsOptionalKeyOf<User | Admin, 'surname'>;
|
|
105
|
+
//=> boolean
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
@category Type Guard
|
|
109
|
+
@category Utilities
|
|
110
|
+
*/
|
|
111
|
+
type IsOptionalKeyOf<Type extends object, Key extends keyof Type> = IsAny<Type | Key> extends true ? never : Key extends keyof Type ? Type extends Record<Key, Type[Key]> ? false : true : false;
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/optional-keys-of.d.ts
|
|
114
|
+
/**
|
|
115
|
+
Extract all optional keys from the given type.
|
|
116
|
+
|
|
117
|
+
This is useful when you want to create a new type that contains different type values for the optional keys only.
|
|
118
|
+
|
|
119
|
+
@example
|
|
120
|
+
```
|
|
121
|
+
import type {OptionalKeysOf, Except} from 'type-fest';
|
|
122
|
+
|
|
123
|
+
type User = {
|
|
124
|
+
name: string;
|
|
125
|
+
surname: string;
|
|
126
|
+
|
|
127
|
+
luckyNumber?: number;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const REMOVE_FIELD = Symbol('remove field symbol');
|
|
131
|
+
type UpdateOperation<Entity extends object> = Except<Partial<Entity>, OptionalKeysOf<Entity>> & {
|
|
132
|
+
[Key in OptionalKeysOf<Entity>]?: Entity[Key] | typeof REMOVE_FIELD;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const update1: UpdateOperation<User> = {
|
|
136
|
+
name: 'Alice',
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const update2: UpdateOperation<User> = {
|
|
140
|
+
name: 'Bob',
|
|
141
|
+
luckyNumber: REMOVE_FIELD,
|
|
142
|
+
};
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
@category Utilities
|
|
146
|
+
*/
|
|
147
|
+
type OptionalKeysOf<Type extends object> = Type extends unknown // For distributing `Type`
|
|
148
|
+
? (keyof { [Key in keyof Type as IsOptionalKeyOf<Type, Key> extends false ? never : Key]: never }) & keyof Type // Intersect with `keyof Type` to ensure result of `OptionalKeysOf<Type>` is always assignable to `keyof Type`
|
|
149
|
+
: never;
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/required-keys-of.d.ts
|
|
152
|
+
/**
|
|
153
|
+
Extract all required keys from the given type.
|
|
154
|
+
|
|
155
|
+
This is useful when you want to create a new type that contains different type values for the required keys only or use the list of keys for validation purposes, etc...
|
|
156
|
+
|
|
157
|
+
@example
|
|
158
|
+
```
|
|
159
|
+
import type {RequiredKeysOf} from 'type-fest';
|
|
160
|
+
|
|
161
|
+
declare function createValidation<
|
|
162
|
+
Entity extends object,
|
|
163
|
+
Key extends RequiredKeysOf<Entity> = RequiredKeysOf<Entity>,
|
|
164
|
+
>(field: Key, validator: (value: Entity[Key]) => boolean): (entity: Entity) => boolean;
|
|
165
|
+
|
|
166
|
+
type User = {
|
|
167
|
+
name: string;
|
|
168
|
+
surname: string;
|
|
169
|
+
luckyNumber?: number;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const validator1 = createValidation<User>('name', value => value.length < 25);
|
|
173
|
+
const validator2 = createValidation<User>('surname', value => value.length < 25);
|
|
174
|
+
|
|
175
|
+
// @ts-expect-error
|
|
176
|
+
const validator3 = createValidation<User>('luckyNumber', value => value > 0);
|
|
177
|
+
// Error: Argument of type '"luckyNumber"' is not assignable to parameter of type '"name" | "surname"'.
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
@category Utilities
|
|
181
|
+
*/
|
|
182
|
+
type RequiredKeysOf<Type extends object> = Type extends unknown // For distributing `Type`
|
|
183
|
+
? Exclude<keyof Type, OptionalKeysOf<Type>> : never;
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/is-never.d.ts
|
|
186
|
+
/**
|
|
187
|
+
Returns a boolean for whether the given type is `never`.
|
|
188
|
+
|
|
189
|
+
@link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
|
|
190
|
+
@link https://stackoverflow.com/a/53984913/10292952
|
|
191
|
+
@link https://www.zhenghao.io/posts/ts-never
|
|
192
|
+
|
|
193
|
+
Useful in type utilities, such as checking if something does not occur.
|
|
194
|
+
|
|
195
|
+
@example
|
|
196
|
+
```
|
|
197
|
+
import type {IsNever, And} from 'type-fest';
|
|
198
|
+
|
|
199
|
+
type A = IsNever<never>;
|
|
200
|
+
//=> true
|
|
201
|
+
|
|
202
|
+
type B = IsNever<any>;
|
|
203
|
+
//=> false
|
|
204
|
+
|
|
205
|
+
type C = IsNever<unknown>;
|
|
206
|
+
//=> false
|
|
207
|
+
|
|
208
|
+
type D = IsNever<never[]>;
|
|
209
|
+
//=> false
|
|
210
|
+
|
|
211
|
+
type E = IsNever<object>;
|
|
212
|
+
//=> false
|
|
213
|
+
|
|
214
|
+
type F = IsNever<string>;
|
|
215
|
+
//=> false
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
@example
|
|
219
|
+
```
|
|
220
|
+
import type {IsNever} from 'type-fest';
|
|
221
|
+
|
|
222
|
+
type IsTrue<T> = T extends true ? true : false;
|
|
223
|
+
|
|
224
|
+
// When a distributive conditional is instantiated with `never`, the entire conditional results in `never`.
|
|
225
|
+
type A = IsTrue<never>;
|
|
226
|
+
//=> never
|
|
227
|
+
|
|
228
|
+
// If you don't want that behaviour, you can explicitly add an `IsNever` check before the distributive conditional.
|
|
229
|
+
type IsTrueFixed<T> =
|
|
230
|
+
IsNever<T> extends true ? false : T extends true ? true : false;
|
|
231
|
+
|
|
232
|
+
type B = IsTrueFixed<never>;
|
|
233
|
+
//=> false
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
@category Type Guard
|
|
237
|
+
@category Utilities
|
|
238
|
+
*/
|
|
239
|
+
type IsNever<T> = [T] extends [never] ? true : false;
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/if.d.ts
|
|
242
|
+
/**
|
|
243
|
+
An if-else-like type that resolves depending on whether the given `boolean` type is `true` or `false`.
|
|
244
|
+
|
|
245
|
+
Use-cases:
|
|
246
|
+
- You can use this in combination with `Is*` types to create an if-else-like experience. For example, `If<IsAny<any>, 'is any', 'not any'>`.
|
|
247
|
+
|
|
248
|
+
Note:
|
|
249
|
+
- Returns a union of if branch and else branch if the given type is `boolean` or `any`. For example, `If<boolean, 'Y', 'N'>` will return `'Y' | 'N'`.
|
|
250
|
+
- Returns the else branch if the given type is `never`. For example, `If<never, 'Y', 'N'>` will return `'N'`.
|
|
251
|
+
|
|
252
|
+
@example
|
|
253
|
+
```
|
|
254
|
+
import type {If} from 'type-fest';
|
|
255
|
+
|
|
256
|
+
type A = If<true, 'yes', 'no'>;
|
|
257
|
+
//=> 'yes'
|
|
258
|
+
|
|
259
|
+
type B = If<false, 'yes', 'no'>;
|
|
260
|
+
//=> 'no'
|
|
261
|
+
|
|
262
|
+
type C = If<boolean, 'yes', 'no'>;
|
|
263
|
+
//=> 'yes' | 'no'
|
|
264
|
+
|
|
265
|
+
type D = If<any, 'yes', 'no'>;
|
|
266
|
+
//=> 'yes' | 'no'
|
|
267
|
+
|
|
268
|
+
type E = If<never, 'yes', 'no'>;
|
|
269
|
+
//=> 'no'
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
@example
|
|
273
|
+
```
|
|
274
|
+
import type {If, IsAny, IsNever} from 'type-fest';
|
|
275
|
+
|
|
276
|
+
type A = If<IsAny<unknown>, 'is any', 'not any'>;
|
|
277
|
+
//=> 'not any'
|
|
278
|
+
|
|
279
|
+
type B = If<IsNever<never>, 'is never', 'not never'>;
|
|
280
|
+
//=> 'is never'
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
@example
|
|
284
|
+
```
|
|
285
|
+
import type {If, IsEqual} from 'type-fest';
|
|
286
|
+
|
|
287
|
+
type IfEqual<T, U, IfBranch, ElseBranch> = If<IsEqual<T, U>, IfBranch, ElseBranch>;
|
|
288
|
+
|
|
289
|
+
type A = IfEqual<string, string, 'equal', 'not equal'>;
|
|
290
|
+
//=> 'equal'
|
|
291
|
+
|
|
292
|
+
type B = IfEqual<string, number, 'equal', 'not equal'>;
|
|
293
|
+
//=> 'not equal'
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Note: Sometimes using the `If` type can make an implementation non–tail-recursive, which can impact performance. In such cases, it’s better to use a conditional directly. Refer to the following example:
|
|
297
|
+
|
|
298
|
+
@example
|
|
299
|
+
```
|
|
300
|
+
import type {If, IsEqual, StringRepeat} from 'type-fest';
|
|
301
|
+
|
|
302
|
+
type HundredZeroes = StringRepeat<'0', 100>;
|
|
303
|
+
|
|
304
|
+
// The following implementation is not tail recursive
|
|
305
|
+
type Includes<S extends string, Char extends string> =
|
|
306
|
+
S extends `${infer First}${infer Rest}`
|
|
307
|
+
? If<IsEqual<First, Char>,
|
|
308
|
+
'found',
|
|
309
|
+
Includes<Rest, Char>>
|
|
310
|
+
: 'not found';
|
|
311
|
+
|
|
312
|
+
// Hence, instantiations with long strings will fail
|
|
313
|
+
// @ts-expect-error
|
|
314
|
+
type Fails = Includes<HundredZeroes, '1'>;
|
|
315
|
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
316
|
+
// Error: Type instantiation is excessively deep and possibly infinite.
|
|
317
|
+
|
|
318
|
+
// However, if we use a simple conditional instead of `If`, the implementation becomes tail-recursive
|
|
319
|
+
type IncludesWithoutIf<S extends string, Char extends string> =
|
|
320
|
+
S extends `${infer First}${infer Rest}`
|
|
321
|
+
? IsEqual<First, Char> extends true
|
|
322
|
+
? 'found'
|
|
323
|
+
: IncludesWithoutIf<Rest, Char>
|
|
324
|
+
: 'not found';
|
|
325
|
+
|
|
326
|
+
// Now, instantiations with long strings will work
|
|
327
|
+
type Works = IncludesWithoutIf<HundredZeroes, '1'>;
|
|
328
|
+
//=> 'not found'
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
@category Type Guard
|
|
332
|
+
@category Utilities
|
|
333
|
+
*/
|
|
334
|
+
type If<Type extends boolean, IfBranch, ElseBranch> = IsNever<Type> extends true ? ElseBranch : Type extends true ? IfBranch : ElseBranch;
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/internal/type.d.ts
|
|
337
|
+
/**
|
|
338
|
+
Matches any primitive, `void`, `Date`, or `RegExp` value.
|
|
339
|
+
*/
|
|
340
|
+
type BuiltIns = Primitive | void | Date | RegExp;
|
|
341
|
+
/**
|
|
342
|
+
Returns a boolean for whether the given `boolean` is not `false`.
|
|
343
|
+
*/
|
|
344
|
+
type IsNotFalse<T extends boolean> = [T] extends [false] ? false : true;
|
|
345
|
+
/**
|
|
346
|
+
Returns a boolean for whether the given type is primitive value or primitive type.
|
|
347
|
+
|
|
348
|
+
@example
|
|
349
|
+
```
|
|
350
|
+
type A = IsPrimitive<'string'>;
|
|
351
|
+
//=> true
|
|
352
|
+
|
|
353
|
+
type B = IsPrimitive<string>;
|
|
354
|
+
//=> true
|
|
355
|
+
|
|
356
|
+
type C = IsPrimitive<Object>;
|
|
357
|
+
//=> false
|
|
358
|
+
```
|
|
359
|
+
*/
|
|
360
|
+
type IsPrimitive<T> = [T] extends [Primitive] ? true : false;
|
|
361
|
+
/**
|
|
362
|
+
An if-else-like type that resolves depending on whether the given type is `any` or `never`.
|
|
363
|
+
|
|
364
|
+
@example
|
|
365
|
+
```
|
|
366
|
+
// When `T` is a NOT `any` or `never` (like `string`) => Returns `IfNotAnyOrNever` branch
|
|
367
|
+
type A = IfNotAnyOrNever<string, 'VALID', 'IS_ANY', 'IS_NEVER'>;
|
|
368
|
+
//=> 'VALID'
|
|
369
|
+
|
|
370
|
+
// When `T` is `any` => Returns `IfAny` branch
|
|
371
|
+
type B = IfNotAnyOrNever<any, 'VALID', 'IS_ANY', 'IS_NEVER'>;
|
|
372
|
+
//=> 'IS_ANY'
|
|
373
|
+
|
|
374
|
+
// When `T` is `never` => Returns `IfNever` branch
|
|
375
|
+
type C = IfNotAnyOrNever<never, 'VALID', 'IS_ANY', 'IS_NEVER'>;
|
|
376
|
+
//=> 'IS_NEVER'
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Note: Wrapping a tail-recursive type with `IfNotAnyOrNever` makes the implementation non-tail-recursive. To fix this, move the recursion into a helper type. Refer to the following example:
|
|
380
|
+
|
|
381
|
+
@example
|
|
382
|
+
```ts
|
|
383
|
+
import type {StringRepeat} from 'type-fest';
|
|
384
|
+
|
|
385
|
+
type NineHundredNinetyNineSpaces = StringRepeat<' ', 999>;
|
|
386
|
+
|
|
387
|
+
// The following implementation is not tail recursive
|
|
388
|
+
type TrimLeft<S extends string> = IfNotAnyOrNever<S, S extends ` ${infer R}` ? TrimLeft<R> : S>;
|
|
389
|
+
|
|
390
|
+
// Hence, instantiations with long strings will fail
|
|
391
|
+
// @ts-expect-error
|
|
392
|
+
type T1 = TrimLeft<NineHundredNinetyNineSpaces>;
|
|
393
|
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
394
|
+
// Error: Type instantiation is excessively deep and possibly infinite.
|
|
395
|
+
|
|
396
|
+
// To fix this, move the recursion into a helper type
|
|
397
|
+
type TrimLeftOptimised<S extends string> = IfNotAnyOrNever<S, _TrimLeftOptimised<S>>;
|
|
398
|
+
|
|
399
|
+
type _TrimLeftOptimised<S extends string> = S extends ` ${infer R}` ? _TrimLeftOptimised<R> : S;
|
|
400
|
+
|
|
401
|
+
type T2 = TrimLeftOptimised<NineHundredNinetyNineSpaces>;
|
|
402
|
+
//=> ''
|
|
403
|
+
```
|
|
404
|
+
*/
|
|
405
|
+
type IfNotAnyOrNever<T, IfNotAnyOrNever, IfAny = any, IfNever = never> = If<IsAny<T>, IfAny, If<IsNever<T>, IfNever, IfNotAnyOrNever>>;
|
|
406
|
+
//#endregion
|
|
407
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/numeric.d.ts
|
|
408
|
+
type _Numeric = number | bigint;
|
|
409
|
+
//#endregion
|
|
410
|
+
//#region ../../node_modules/.pnpm/tagged-tag@1.0.0/node_modules/tagged-tag/index.d.ts
|
|
411
|
+
declare const tag: unique symbol;
|
|
412
|
+
//#endregion
|
|
413
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/tagged.d.ts
|
|
414
|
+
// eslint-disable-next-line type-fest/require-exported-types
|
|
415
|
+
type TagContainer<Token> = {
|
|
416
|
+
readonly [tag]: Token;
|
|
417
|
+
};
|
|
418
|
+
type Tag<Token extends PropertyKey, TagMetadata> = TagContainer<{ [K in Token]: TagMetadata }>;
|
|
419
|
+
/**
|
|
420
|
+
Create a [tagged type](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d) that can support [multiple tags](https://github.com/sindresorhus/type-fest/issues/665) and [per-tag metadata](https://medium.com/@ethanresnick/advanced-typescript-tagged-types-improved-with-type-level-metadata-5072fc125fcf).
|
|
421
|
+
|
|
422
|
+
A type returned by `Tagged` can be passed to `Tagged` again, to create a type with multiple tags.
|
|
423
|
+
|
|
424
|
+
A tag's name is usually a string (and must be a string, number, or symbol), but each application of a tag can also contain an arbitrary type as its "metadata". See {@link GetTagMetadata} for examples and explanation.
|
|
425
|
+
|
|
426
|
+
A type `A` returned by `Tagged` is assignable to another type `B` returned by `Tagged` if and only if:
|
|
427
|
+
- the underlying (untagged) type of `A` is assignable to the underlying type of `B`;
|
|
428
|
+
- `A` contains at least all the tags `B` has;
|
|
429
|
+
- and the metadata type for each of `A`'s tags is assignable to the metadata type of `B`'s corresponding tag.
|
|
430
|
+
|
|
431
|
+
There have been several discussions about adding similar features to TypeScript. Unfortunately, nothing has (yet) moved forward:
|
|
432
|
+
- [Microsoft/TypeScript#202](https://github.com/microsoft/TypeScript/issues/202)
|
|
433
|
+
- [Microsoft/TypeScript#4895](https://github.com/microsoft/TypeScript/issues/4895)
|
|
434
|
+
- [Microsoft/TypeScript#33290](https://github.com/microsoft/TypeScript/pull/33290)
|
|
435
|
+
|
|
436
|
+
@example
|
|
437
|
+
```
|
|
438
|
+
import type {Tagged} from 'type-fest';
|
|
439
|
+
|
|
440
|
+
type AccountNumber = Tagged<number, 'AccountNumber'>;
|
|
441
|
+
type AccountBalance = Tagged<number, 'AccountBalance'>;
|
|
442
|
+
|
|
443
|
+
function createAccountNumber(): AccountNumber {
|
|
444
|
+
// As you can see, casting from a `number` (the underlying type being tagged) is allowed.
|
|
445
|
+
return 2 as AccountNumber;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
declare function getMoneyForAccount(accountNumber: AccountNumber): AccountBalance;
|
|
449
|
+
|
|
450
|
+
// This will compile successfully.
|
|
451
|
+
getMoneyForAccount(createAccountNumber());
|
|
452
|
+
|
|
453
|
+
// But this won't, because it has to be explicitly passed as an `AccountNumber` type!
|
|
454
|
+
// Critically, you could not accidentally use an `AccountBalance` as an `AccountNumber`.
|
|
455
|
+
// @ts-expect-error
|
|
456
|
+
getMoneyForAccount(2);
|
|
457
|
+
|
|
458
|
+
// You can also use tagged values like their underlying, untagged type.
|
|
459
|
+
// I.e., this will compile successfully because an `AccountNumber` can be used as a regular `number`.
|
|
460
|
+
// In this sense, the underlying base type is not hidden, which differentiates tagged types from opaque types in other languages.
|
|
461
|
+
const accountNumber = createAccountNumber() + 2;
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
@example
|
|
465
|
+
```
|
|
466
|
+
import type {Tagged} from 'type-fest';
|
|
467
|
+
|
|
468
|
+
// You can apply multiple tags to a type by using `Tagged` repeatedly.
|
|
469
|
+
type Url = Tagged<string, 'URL'>;
|
|
470
|
+
type SpecialCacheKey = Tagged<Url, 'SpecialCacheKey'>;
|
|
471
|
+
|
|
472
|
+
// You can also pass a union of tag names, so this is equivalent to the above, although it doesn't give you the ability to assign distinct metadata to each tag.
|
|
473
|
+
type SpecialCacheKey2 = Tagged<string, 'URL' | 'SpecialCacheKey'>;
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
@category Type
|
|
477
|
+
*/
|
|
478
|
+
type Tagged<Type, TagName extends PropertyKey, TagMetadata = never> = Type & Tag<TagName, TagMetadata>;
|
|
479
|
+
/**
|
|
480
|
+
Get the untagged portion of a tagged type created with `Tagged`.
|
|
481
|
+
|
|
482
|
+
Why is this necessary?
|
|
483
|
+
|
|
484
|
+
1. Use a `Tagged` type as object keys
|
|
485
|
+
2. Prevent TS4058 error: "Return type of exported function has or is using name X from external module Y but cannot be named"
|
|
486
|
+
|
|
487
|
+
@example
|
|
488
|
+
```
|
|
489
|
+
import type {Tagged, UnwrapTagged} from 'type-fest';
|
|
490
|
+
|
|
491
|
+
type AccountType = Tagged<'SAVINGS' | 'CHECKING', 'AccountType'>;
|
|
492
|
+
|
|
493
|
+
const moneyByAccountType: Record<UnwrapTagged<AccountType>, number> = {
|
|
494
|
+
SAVINGS: 99,
|
|
495
|
+
CHECKING: 0.1,
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
// Without UnwrapTagged, the following expression would throw a type error.
|
|
499
|
+
const money = moneyByAccountType.SAVINGS; // TS error: Property 'SAVINGS' does not exist
|
|
500
|
+
|
|
501
|
+
// Attempting to pass a non-Tagged type to UnwrapTagged will raise a type error.
|
|
502
|
+
// @ts-expect-error
|
|
503
|
+
type WontWork = UnwrapTagged<string>;
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
@category Type
|
|
507
|
+
*/
|
|
508
|
+
type UnwrapTagged<TaggedType extends Tag<PropertyKey, any>> = RemoveAllTags<TaggedType>;
|
|
509
|
+
type RemoveAllTags<T> = T extends Tag<PropertyKey, any> ? { [ThisTag in keyof T[typeof tag]]: T extends Tagged<infer Type, ThisTag, T[typeof tag][ThisTag]> ? RemoveAllTags<Type> : never }[keyof T[typeof tag]] : T;
|
|
510
|
+
/**
|
|
511
|
+
Note: The `Opaque` type is deprecated in favor of `Tagged`.
|
|
512
|
+
|
|
513
|
+
Attach a "tag" to an arbitrary type. This allows you to create distinct types, that aren't assignable to one another, for runtime values that would otherwise have the same type. (See examples.)
|
|
514
|
+
|
|
515
|
+
The generic type parameters can be anything.
|
|
516
|
+
|
|
517
|
+
Note that `Opaque` is somewhat of a misnomer here, in that, unlike [some alternative implementations](https://github.com/microsoft/TypeScript/issues/4895#issuecomment-425132582), the original, untagged type is not actually hidden. (E.g., functions that accept the untagged type can still be called with the "opaque" version -- but not vice-versa.)
|
|
518
|
+
|
|
519
|
+
Also note that this implementation is limited to a single tag. If you want to allow multiple tags, use `Tagged` instead.
|
|
520
|
+
|
|
521
|
+
[Read more about tagged types.](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d)
|
|
522
|
+
|
|
523
|
+
There have been several discussions about adding similar features to TypeScript. Unfortunately, nothing has (yet) moved forward:
|
|
524
|
+
- [Microsoft/TypeScript#202](https://github.com/microsoft/TypeScript/issues/202)
|
|
525
|
+
- [Microsoft/TypeScript#15408](https://github.com/Microsoft/TypeScript/issues/15408)
|
|
526
|
+
- [Microsoft/TypeScript#15807](https://github.com/Microsoft/TypeScript/issues/15807)
|
|
527
|
+
|
|
528
|
+
@example
|
|
529
|
+
```
|
|
530
|
+
import type {Opaque} from 'type-fest';
|
|
531
|
+
|
|
532
|
+
type AccountNumber = Opaque<number, 'AccountNumber'>;
|
|
533
|
+
type AccountBalance = Opaque<number, 'AccountBalance'>;
|
|
534
|
+
|
|
535
|
+
// The `Token` parameter allows the compiler to differentiate between types, whereas "unknown" will not. For example, consider the following structures:
|
|
536
|
+
type ThingOne = Opaque<string>;
|
|
537
|
+
type ThingTwo = Opaque<string>;
|
|
538
|
+
|
|
539
|
+
// To the compiler, these types are allowed to be cast to each other as they have the same underlying type. They are both `string & { __opaque__: unknown }`.
|
|
540
|
+
// To avoid this behaviour, you would instead pass the "Token" parameter, like so.
|
|
541
|
+
type NewThingOne = Opaque<string, 'ThingOne'>;
|
|
542
|
+
type NewThingTwo = Opaque<string, 'ThingTwo'>;
|
|
543
|
+
|
|
544
|
+
// Now they're completely separate types, so the following will fail to compile.
|
|
545
|
+
function createNewThingOne(): NewThingOne {
|
|
546
|
+
// As you can see, casting from a string is still allowed. However, you may not cast NewThingOne to NewThingTwo, and vice versa.
|
|
547
|
+
return 'new thing one' as NewThingOne;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// This will fail to compile, as they are fundamentally different types.
|
|
551
|
+
// @ts-expect-error
|
|
552
|
+
const thingTwo = createNewThingOne() as NewThingTwo;
|
|
553
|
+
|
|
554
|
+
// Here's another example of opaque typing.
|
|
555
|
+
function createAccountNumber(): AccountNumber {
|
|
556
|
+
return 2 as AccountNumber;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
declare function getMoneyForAccount(accountNumber: AccountNumber): AccountBalance;
|
|
560
|
+
|
|
561
|
+
// This will compile successfully.
|
|
562
|
+
getMoneyForAccount(createAccountNumber());
|
|
563
|
+
|
|
564
|
+
// But this won't, because it has to be explicitly passed as an `AccountNumber` type.
|
|
565
|
+
// @ts-expect-error
|
|
566
|
+
getMoneyForAccount(2);
|
|
567
|
+
|
|
568
|
+
// You can use opaque values like they aren't opaque too.
|
|
569
|
+
const accountNumber = createAccountNumber();
|
|
570
|
+
|
|
571
|
+
// This will compile successfully.
|
|
572
|
+
const newAccountNumber = accountNumber + 2;
|
|
573
|
+
|
|
574
|
+
// As a side note, you can (and should) use recursive types for your opaque types to make them stronger and hopefully easier to type.
|
|
575
|
+
type Person = {
|
|
576
|
+
id: Opaque<number, Person>;
|
|
577
|
+
name: string;
|
|
578
|
+
};
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
@category Type
|
|
582
|
+
@deprecated Use {@link Tagged} instead
|
|
583
|
+
*/
|
|
584
|
+
//#endregion
|
|
585
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/is-literal.d.ts
|
|
586
|
+
/**
|
|
587
|
+
Returns a boolean for whether the given type `T` is the specified `LiteralType`.
|
|
588
|
+
|
|
589
|
+
@link https://stackoverflow.com/a/52806744/10292952
|
|
590
|
+
|
|
591
|
+
@example
|
|
592
|
+
```
|
|
593
|
+
type A = LiteralCheck<1, number>;
|
|
594
|
+
//=> true
|
|
595
|
+
|
|
596
|
+
type B = LiteralCheck<number, number>;
|
|
597
|
+
//=> false
|
|
598
|
+
|
|
599
|
+
type C = LiteralCheck<1, string>;
|
|
600
|
+
//=> false
|
|
601
|
+
```
|
|
602
|
+
*/
|
|
603
|
+
type LiteralCheck<T, LiteralType extends Primitive> = (IsNever<T> extends false // Must be wider than `never`
|
|
604
|
+
? [T] extends [LiteralType & infer U] // Remove any branding
|
|
605
|
+
? [U] extends [LiteralType] // Must be narrower than `LiteralType`
|
|
606
|
+
? [LiteralType] extends [U] // Cannot be wider than `LiteralType`
|
|
607
|
+
? false : true : false : false : false);
|
|
608
|
+
/**
|
|
609
|
+
Returns a boolean for whether the given type `T` is one of the specified literal types in `LiteralUnionType`.
|
|
610
|
+
|
|
611
|
+
@example
|
|
612
|
+
```
|
|
613
|
+
type A = LiteralChecks<1, Numeric>;
|
|
614
|
+
//=> true
|
|
615
|
+
|
|
616
|
+
type B = LiteralChecks<1n, Numeric>;
|
|
617
|
+
//=> true
|
|
618
|
+
|
|
619
|
+
type C = LiteralChecks<bigint, Numeric>;
|
|
620
|
+
//=> false
|
|
621
|
+
```
|
|
622
|
+
*/
|
|
623
|
+
type LiteralChecks<T, LiteralUnionType> = (// Conditional type to force union distribution.
|
|
624
|
+
// If `T` is none of the literal types in the union `LiteralUnionType`, then `LiteralCheck<T, LiteralType>` will evaluate to `false` for the whole union.
|
|
625
|
+
// If `T` is one of the literal types in the union, it will evaluate to `boolean` (i.e. `true | false`)
|
|
626
|
+
IsNotFalse<LiteralUnionType extends Primitive ? LiteralCheck<T, LiteralUnionType> : never>);
|
|
627
|
+
/**
|
|
628
|
+
Returns a boolean for whether the given type is a `string` [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types).
|
|
629
|
+
|
|
630
|
+
Useful for:
|
|
631
|
+
- providing strongly-typed string manipulation functions
|
|
632
|
+
- constraining strings to be a string literal
|
|
633
|
+
- type utilities, such as when constructing parsers and ASTs
|
|
634
|
+
|
|
635
|
+
The implementation of this type is inspired by the trick mentioned in this [StackOverflow answer](https://stackoverflow.com/a/68261113/420747).
|
|
636
|
+
|
|
637
|
+
@example
|
|
638
|
+
```
|
|
639
|
+
import type {IsStringLiteral} from 'type-fest';
|
|
640
|
+
|
|
641
|
+
type CapitalizedString<T extends string> = IsStringLiteral<T> extends true ? Capitalize<T> : string;
|
|
642
|
+
|
|
643
|
+
// https://github.com/yankeeinlondon/native-dash/blob/master/src/capitalize.ts
|
|
644
|
+
function capitalize<T extends Readonly<string>>(input: T): CapitalizedString<T> {
|
|
645
|
+
return (input.slice(0, 1).toUpperCase() + input.slice(1)) as CapitalizedString<T>;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
const output = capitalize('hello, world!');
|
|
649
|
+
//=> 'Hello, world!'
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
@example
|
|
653
|
+
```
|
|
654
|
+
// String types with infinite set of possible values return `false`.
|
|
655
|
+
|
|
656
|
+
import type {IsStringLiteral} from 'type-fest';
|
|
657
|
+
|
|
658
|
+
type AllUppercaseStrings = IsStringLiteral<Uppercase<string>>;
|
|
659
|
+
//=> false
|
|
660
|
+
|
|
661
|
+
type StringsStartingWithOn = IsStringLiteral<`on${string}`>;
|
|
662
|
+
//=> false
|
|
663
|
+
|
|
664
|
+
// This behaviour is particularly useful in string manipulation utilities, as infinite string types often require separate handling.
|
|
665
|
+
|
|
666
|
+
type Length<S extends string, Counter extends never[] = []> =
|
|
667
|
+
IsStringLiteral<S> extends false
|
|
668
|
+
? number // return `number` for infinite string types
|
|
669
|
+
: S extends `${string}${infer Tail}`
|
|
670
|
+
? Length<Tail, [...Counter, never]>
|
|
671
|
+
: Counter['length'];
|
|
672
|
+
|
|
673
|
+
type L1 = Length<Lowercase<string>>;
|
|
674
|
+
//=> number
|
|
675
|
+
|
|
676
|
+
type L2 = Length<`${number}`>;
|
|
677
|
+
//=> number
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
@category Type Guard
|
|
681
|
+
@category Utilities
|
|
682
|
+
*/
|
|
683
|
+
type IsStringLiteral<S> = IfNotAnyOrNever<S, _IsStringLiteral<CollapseLiterals<S extends TagContainer<any> ? UnwrapTagged<S> : S>>, false, false>;
|
|
684
|
+
type _IsStringLiteral<S> = // If `T` is an infinite string type (e.g., `on${string}`), `Record<T, never>` produces an index signature,
|
|
685
|
+
// and since `{}` extends index signatures, the result becomes `false`.
|
|
686
|
+
S extends string ? {} extends Record<S, never> ? false : true : false;
|
|
687
|
+
/**
|
|
688
|
+
Returns a boolean for whether the given type is a `number` or `bigint` [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types).
|
|
689
|
+
|
|
690
|
+
Useful for:
|
|
691
|
+
- providing strongly-typed functions when given literal arguments
|
|
692
|
+
- type utilities, such as when constructing parsers and ASTs
|
|
693
|
+
|
|
694
|
+
@example
|
|
695
|
+
```
|
|
696
|
+
import type {IsNumericLiteral, IsStringLiteral} from 'type-fest';
|
|
697
|
+
|
|
698
|
+
// https://github.com/inocan-group/inferred-types/blob/master/modules/types/src/boolean-logic/operators/EndsWith.ts
|
|
699
|
+
type EndsWith<TValue, TEndsWith extends string> =
|
|
700
|
+
TValue extends string
|
|
701
|
+
? IsStringLiteral<TEndsWith> extends true
|
|
702
|
+
? IsStringLiteral<TValue> extends true
|
|
703
|
+
? TValue extends `${string}${TEndsWith}`
|
|
704
|
+
? true
|
|
705
|
+
: false
|
|
706
|
+
: boolean
|
|
707
|
+
: boolean
|
|
708
|
+
: TValue extends number
|
|
709
|
+
? IsNumericLiteral<TValue> extends true
|
|
710
|
+
? EndsWith<`${TValue}`, TEndsWith>
|
|
711
|
+
: false
|
|
712
|
+
: false;
|
|
713
|
+
|
|
714
|
+
function endsWith<Input extends string | number, End extends string>(input: Input, end: End) {
|
|
715
|
+
return `${input}`.endsWith(end) as EndsWith<Input, End>;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
endsWith('abc', 'c');
|
|
719
|
+
//=> true
|
|
720
|
+
|
|
721
|
+
endsWith(123_456, '456');
|
|
722
|
+
//=> true
|
|
723
|
+
|
|
724
|
+
const end = '123' as string;
|
|
725
|
+
|
|
726
|
+
endsWith('abc123', end);
|
|
727
|
+
//=> boolean
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
@category Type Guard
|
|
731
|
+
@category Utilities
|
|
732
|
+
*/
|
|
733
|
+
type IsNumericLiteral<T> = LiteralChecks<T, _Numeric>;
|
|
734
|
+
/**
|
|
735
|
+
Returns a boolean for whether the given type is a `true` or `false` [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types).
|
|
736
|
+
|
|
737
|
+
Useful for:
|
|
738
|
+
- providing strongly-typed functions when given literal arguments
|
|
739
|
+
- type utilities, such as when constructing parsers and ASTs
|
|
740
|
+
|
|
741
|
+
@example
|
|
742
|
+
```
|
|
743
|
+
import type {IsBooleanLiteral} from 'type-fest';
|
|
744
|
+
|
|
745
|
+
const id = 123;
|
|
746
|
+
|
|
747
|
+
type GetId<AsString extends boolean> =
|
|
748
|
+
IsBooleanLiteral<AsString> extends true
|
|
749
|
+
? AsString extends true
|
|
750
|
+
? `${typeof id}`
|
|
751
|
+
: typeof id
|
|
752
|
+
: number | string;
|
|
753
|
+
|
|
754
|
+
function getId<AsString extends boolean = false>(options?: {asString: AsString}) {
|
|
755
|
+
return (options?.asString ? `${id}` : id) as GetId<AsString>;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const numberId = getId();
|
|
759
|
+
//=> 123
|
|
760
|
+
|
|
761
|
+
const stringId = getId({asString: true});
|
|
762
|
+
//=> '123'
|
|
763
|
+
|
|
764
|
+
declare const runtimeBoolean: boolean;
|
|
765
|
+
const eitherId = getId({asString: runtimeBoolean});
|
|
766
|
+
//=> string | number
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
@category Type Guard
|
|
770
|
+
@category Utilities
|
|
771
|
+
*/
|
|
772
|
+
type IsBooleanLiteral<T> = LiteralCheck<T, boolean>;
|
|
773
|
+
/**
|
|
774
|
+
Returns a boolean for whether the given type is a `symbol` [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types).
|
|
775
|
+
|
|
776
|
+
Useful for:
|
|
777
|
+
- providing strongly-typed functions when given literal arguments
|
|
778
|
+
- type utilities, such as when constructing parsers and ASTs
|
|
779
|
+
|
|
780
|
+
@example
|
|
781
|
+
```
|
|
782
|
+
import type {IsSymbolLiteral} from 'type-fest';
|
|
783
|
+
|
|
784
|
+
type Get<Object_ extends Record<symbol, number>, Key extends keyof Object_> =
|
|
785
|
+
IsSymbolLiteral<Key> extends true
|
|
786
|
+
? Object_[Key]
|
|
787
|
+
: number;
|
|
788
|
+
|
|
789
|
+
function get<Object_ extends Record<symbol, number>, Key extends keyof Object_>(o: Object_, key: Key) {
|
|
790
|
+
return o[key] as Get<Object_, Key>;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
const symbolLiteral = Symbol('literal');
|
|
794
|
+
let symbolValue = Symbol('value1');
|
|
795
|
+
symbolValue = Symbol('value2');
|
|
796
|
+
|
|
797
|
+
get({[symbolLiteral]: 1} as const, symbolLiteral);
|
|
798
|
+
//=> 1
|
|
799
|
+
|
|
800
|
+
get({[symbolValue]: 1} as const, symbolValue);
|
|
801
|
+
//=> number
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
@category Type Guard
|
|
805
|
+
@category Utilities
|
|
806
|
+
*/
|
|
807
|
+
type IsSymbolLiteral<T> = LiteralCheck<T, symbol>;
|
|
808
|
+
/** Helper type for `IsLiteral`. */
|
|
809
|
+
type IsLiteralUnion<T> = IsStringLiteral<T> | IsNumericLiteral<T> | IsBooleanLiteral<T> | IsSymbolLiteral<T>;
|
|
810
|
+
/**
|
|
811
|
+
Returns a boolean for whether the given type is a [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types).
|
|
812
|
+
|
|
813
|
+
Useful for:
|
|
814
|
+
- providing strongly-typed functions when given literal arguments
|
|
815
|
+
- type utilities, such as when constructing parsers and ASTs
|
|
816
|
+
|
|
817
|
+
@example
|
|
818
|
+
```
|
|
819
|
+
import type {IsLiteral} from 'type-fest';
|
|
820
|
+
|
|
821
|
+
type A = IsLiteral<1>;
|
|
822
|
+
//=> true
|
|
823
|
+
|
|
824
|
+
type B = IsLiteral<number>;
|
|
825
|
+
//=> false
|
|
826
|
+
|
|
827
|
+
type C = IsLiteral<1n>;
|
|
828
|
+
//=> true
|
|
829
|
+
|
|
830
|
+
type D = IsLiteral<bigint>;
|
|
831
|
+
//=> false
|
|
832
|
+
|
|
833
|
+
type E = IsLiteral<'type-fest'>;
|
|
834
|
+
//=> true
|
|
835
|
+
|
|
836
|
+
type F = IsLiteral<string>;
|
|
837
|
+
//=> false
|
|
838
|
+
|
|
839
|
+
type G = IsLiteral<`on${string}`>;
|
|
840
|
+
//=> false
|
|
841
|
+
|
|
842
|
+
declare const symbolLiteral: unique symbol;
|
|
843
|
+
type H = IsLiteral<typeof symbolLiteral>;
|
|
844
|
+
//=> true
|
|
845
|
+
|
|
846
|
+
type I = IsLiteral<symbol>;
|
|
847
|
+
//=> false
|
|
848
|
+
|
|
849
|
+
type J = IsLiteral<true>;
|
|
850
|
+
//=> true
|
|
851
|
+
|
|
852
|
+
type K = IsLiteral<boolean>;
|
|
853
|
+
//=> false
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
@category Type Guard
|
|
857
|
+
@category Utilities
|
|
858
|
+
*/
|
|
859
|
+
type IsLiteral<T> = IsPrimitive<T> extends true ? IsNotFalse<IsLiteralUnion<T>> : false;
|
|
860
|
+
//#endregion
|
|
861
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/is-null.d.ts
|
|
862
|
+
/**
|
|
863
|
+
Returns a boolean for whether the given type is `null`.
|
|
864
|
+
|
|
865
|
+
@example
|
|
866
|
+
```
|
|
867
|
+
import type {IsNull} from 'type-fest';
|
|
868
|
+
|
|
869
|
+
type NonNullFallback<T, Fallback> = IsNull<T> extends true ? Fallback : T;
|
|
870
|
+
|
|
871
|
+
type Example1 = NonNullFallback<null, string>;
|
|
872
|
+
//=> string
|
|
873
|
+
|
|
874
|
+
type Example2 = NonNullFallback<number, string>;
|
|
875
|
+
//=> number
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
@category Type Guard
|
|
879
|
+
@category Utilities
|
|
880
|
+
*/
|
|
881
|
+
type IsNull<T> = [T] extends [null] ? true : false;
|
|
882
|
+
//#endregion
|
|
883
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/is-unknown.d.ts
|
|
884
|
+
/**
|
|
885
|
+
Returns a boolean for whether the given type is `unknown`.
|
|
886
|
+
|
|
887
|
+
@link https://github.com/dsherret/conditional-type-checks/pull/16
|
|
888
|
+
|
|
889
|
+
Useful in type utilities, such as when dealing with unknown data from API calls.
|
|
890
|
+
|
|
891
|
+
@example
|
|
892
|
+
```
|
|
893
|
+
import type {IsUnknown} from 'type-fest';
|
|
894
|
+
|
|
895
|
+
type A = IsUnknown<unknown>;
|
|
896
|
+
//=> true
|
|
897
|
+
|
|
898
|
+
type B = IsUnknown<any>;
|
|
899
|
+
//=> false
|
|
900
|
+
|
|
901
|
+
type C = IsUnknown<never>;
|
|
902
|
+
//=> false
|
|
903
|
+
|
|
904
|
+
type D = IsUnknown<unknown[]>;
|
|
905
|
+
//=> false
|
|
906
|
+
|
|
907
|
+
type E = IsUnknown<object>;
|
|
908
|
+
//=> false
|
|
909
|
+
|
|
910
|
+
type F = IsUnknown<string>;
|
|
911
|
+
//=> false
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
@category Utilities
|
|
915
|
+
*/
|
|
916
|
+
type IsUnknown<T> = (unknown extends T // `T` can be `unknown` or `any`
|
|
917
|
+
? IsNull<T> extends false // `any` can be `null`, but `unknown` can't be
|
|
918
|
+
? true : false : false);
|
|
919
|
+
//#endregion
|
|
920
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/internal/keys.d.ts
|
|
921
|
+
/**
|
|
922
|
+
Utility type to retrieve only literal keys from type.
|
|
923
|
+
*/
|
|
924
|
+
type LiteralKeyOf<T> = keyof { [K in keyof T as IsLiteral<K> extends true ? K : never]-?: never };
|
|
925
|
+
//#endregion
|
|
926
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/simplify.d.ts
|
|
2
927
|
/**
|
|
3
928
|
Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.
|
|
4
929
|
|
|
@@ -33,31 +958,671 @@ interface SomeInterface {
|
|
|
33
958
|
bar?: string;
|
|
34
959
|
baz: number | undefined;
|
|
35
960
|
}
|
|
36
|
-
|
|
37
|
-
type SomeType = {
|
|
38
|
-
foo: number;
|
|
39
|
-
bar?: string;
|
|
40
|
-
baz: number | undefined;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const literal = {foo: 123, bar: 'hello', baz: 456};
|
|
44
|
-
const someType: SomeType = literal;
|
|
45
|
-
const someInterface: SomeInterface = literal;
|
|
46
|
-
|
|
47
|
-
declare function fn(object: Record<string, unknown>): void;
|
|
48
|
-
|
|
49
|
-
fn(literal); // Good: literal object type is sealed
|
|
50
|
-
fn(someType); // Good: type is sealed
|
|
51
|
-
// @ts-expect-error
|
|
52
|
-
fn(someInterface); // Error: Index signature for type 'string' is missing in type 'someInterface'. Because `interface` can be re-opened
|
|
53
|
-
fn(someInterface as Simplify<SomeInterface>); // Good: transform an `interface` into a `type`
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
@link https://github.com/microsoft/TypeScript/issues/15300
|
|
57
|
-
@see {@link SimplifyDeep}
|
|
58
|
-
@category Object
|
|
59
|
-
*/
|
|
60
|
-
type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {};
|
|
961
|
+
|
|
962
|
+
type SomeType = {
|
|
963
|
+
foo: number;
|
|
964
|
+
bar?: string;
|
|
965
|
+
baz: number | undefined;
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
const literal = {foo: 123, bar: 'hello', baz: 456};
|
|
969
|
+
const someType: SomeType = literal;
|
|
970
|
+
const someInterface: SomeInterface = literal;
|
|
971
|
+
|
|
972
|
+
declare function fn(object: Record<string, unknown>): void;
|
|
973
|
+
|
|
974
|
+
fn(literal); // Good: literal object type is sealed
|
|
975
|
+
fn(someType); // Good: type is sealed
|
|
976
|
+
// @ts-expect-error
|
|
977
|
+
fn(someInterface); // Error: Index signature for type 'string' is missing in type 'someInterface'. Because `interface` can be re-opened
|
|
978
|
+
fn(someInterface as Simplify<SomeInterface>); // Good: transform an `interface` into a `type`
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
@link https://github.com/microsoft/TypeScript/issues/15300
|
|
982
|
+
@see {@link SimplifyDeep}
|
|
983
|
+
@category Object
|
|
984
|
+
*/
|
|
985
|
+
type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {};
|
|
986
|
+
//#endregion
|
|
987
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/is-equal.d.ts
|
|
988
|
+
/**
|
|
989
|
+
Returns a boolean for whether the two given types are equal.
|
|
990
|
+
|
|
991
|
+
@link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
|
|
992
|
+
@link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796
|
|
993
|
+
|
|
994
|
+
Use-cases:
|
|
995
|
+
- If you want to make a conditional branch based on the result of a comparison of two types.
|
|
996
|
+
|
|
997
|
+
@example
|
|
998
|
+
```
|
|
999
|
+
import type {IsEqual} from 'type-fest';
|
|
1000
|
+
|
|
1001
|
+
// This type returns a boolean for whether the given array includes the given item.
|
|
1002
|
+
// `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal.
|
|
1003
|
+
type Includes<Value extends readonly any[], Item> =
|
|
1004
|
+
Value extends readonly [Value[0], ...infer rest]
|
|
1005
|
+
? IsEqual<Value[0], Item> extends true
|
|
1006
|
+
? true
|
|
1007
|
+
: Includes<rest, Item>
|
|
1008
|
+
: false;
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
@category Type Guard
|
|
1012
|
+
@category Utilities
|
|
1013
|
+
*/
|
|
1014
|
+
type IsEqual<A, B> = [A] extends [B] ? [B] extends [A] ? _IsEqual<A, B> : false : false;
|
|
1015
|
+
// This version fails the `equalWrappedTupleIntersectionToBeNeverAndNeverExpanded` test in `test-d/is-equal.ts`.
|
|
1016
|
+
type _IsEqual<A, B> = (<G>() => G extends A & G | G ? 1 : 2) extends (<G>() => G extends B & G | G ? 1 : 2) ? true : false;
|
|
1017
|
+
//#endregion
|
|
1018
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/omit-index-signature.d.ts
|
|
1019
|
+
/**
|
|
1020
|
+
Omit any index signatures from the given object type, leaving only explicitly defined properties.
|
|
1021
|
+
|
|
1022
|
+
This is the counterpart of `PickIndexSignature`.
|
|
1023
|
+
|
|
1024
|
+
Use-cases:
|
|
1025
|
+
- Remove overly permissive signatures from third-party types.
|
|
1026
|
+
|
|
1027
|
+
This type was taken from this [StackOverflow answer](https://stackoverflow.com/a/68261113/420747).
|
|
1028
|
+
|
|
1029
|
+
It relies on the fact that an empty object (`{}`) is assignable to an object with just an index signature, like `Record<string, unknown>`, but not to an object with explicitly defined keys, like `Record<'foo' | 'bar', unknown>`.
|
|
1030
|
+
|
|
1031
|
+
(The actual value type, `unknown`, is irrelevant and could be any type. Only the key type matters.)
|
|
1032
|
+
|
|
1033
|
+
```
|
|
1034
|
+
const indexed: Record<string, unknown> = {}; // Allowed
|
|
1035
|
+
|
|
1036
|
+
// @ts-expect-error
|
|
1037
|
+
const keyed: Record<'foo', unknown> = {}; // Error
|
|
1038
|
+
// TS2739: Type '{}' is missing the following properties from type 'Record<"foo" | "bar", unknown>': foo, bar
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
Instead of causing a type error like the above, you can also use a [conditional type](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html) to test whether a type is assignable to another:
|
|
1042
|
+
|
|
1043
|
+
```
|
|
1044
|
+
type Indexed = {} extends Record<string, unknown>
|
|
1045
|
+
? '✅ `{}` is assignable to `Record<string, unknown>`'
|
|
1046
|
+
: '❌ `{}` is NOT assignable to `Record<string, unknown>`';
|
|
1047
|
+
|
|
1048
|
+
type IndexedResult = Indexed;
|
|
1049
|
+
//=> '✅ `{}` is assignable to `Record<string, unknown>`'
|
|
1050
|
+
|
|
1051
|
+
type Keyed = {} extends Record<'foo' | 'bar', unknown>
|
|
1052
|
+
? '✅ `{}` is assignable to `Record<\'foo\' | \'bar\', unknown>`'
|
|
1053
|
+
: '❌ `{}` is NOT assignable to `Record<\'foo\' | \'bar\', unknown>`';
|
|
1054
|
+
|
|
1055
|
+
type KeyedResult = Keyed;
|
|
1056
|
+
//=> '❌ `{}` is NOT assignable to `Record<\'foo\' | \'bar\', unknown>`'
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
Using a [mapped type](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#further-exploration), you can then check for each `KeyType` of `ObjectType`...
|
|
1060
|
+
|
|
1061
|
+
```
|
|
1062
|
+
type OmitIndexSignature<ObjectType> = {
|
|
1063
|
+
[KeyType in keyof ObjectType // Map each key of `ObjectType`...
|
|
1064
|
+
]: ObjectType[KeyType]; // ...to its original value, i.e. `OmitIndexSignature<Foo> == Foo`.
|
|
1065
|
+
};
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
...whether an empty object (`{}`) would be assignable to an object with that `KeyType` (`Record<KeyType, unknown>`)...
|
|
1069
|
+
|
|
1070
|
+
```
|
|
1071
|
+
type OmitIndexSignature<ObjectType> = {
|
|
1072
|
+
[KeyType in keyof ObjectType
|
|
1073
|
+
// Is `{}` assignable to `Record<KeyType, unknown>`?
|
|
1074
|
+
as {} extends Record<KeyType, unknown>
|
|
1075
|
+
? never // ✅ `{}` is assignable to `Record<KeyType, unknown>`
|
|
1076
|
+
: KeyType // ❌ `{}` is NOT assignable to `Record<KeyType, unknown>`
|
|
1077
|
+
]: ObjectType[KeyType];
|
|
1078
|
+
};
|
|
1079
|
+
```
|
|
1080
|
+
|
|
1081
|
+
If `{}` is assignable, it means that `KeyType` is an index signature and we want to remove it. If it is not assignable, `KeyType` is a "real" key and we want to keep it.
|
|
1082
|
+
|
|
1083
|
+
@example
|
|
1084
|
+
```
|
|
1085
|
+
import type {OmitIndexSignature} from 'type-fest';
|
|
1086
|
+
|
|
1087
|
+
type Example = {
|
|
1088
|
+
// These index signatures will be removed.
|
|
1089
|
+
[x: string]: any;
|
|
1090
|
+
[x: number]: any;
|
|
1091
|
+
[x: symbol]: any;
|
|
1092
|
+
[x: `head-${string}`]: string;
|
|
1093
|
+
[x: `${string}-tail`]: string;
|
|
1094
|
+
[x: `head-${string}-tail`]: string;
|
|
1095
|
+
[x: `${bigint}`]: string;
|
|
1096
|
+
[x: `embedded-${number}`]: string;
|
|
1097
|
+
|
|
1098
|
+
// These explicitly defined keys will remain.
|
|
1099
|
+
foo: 'bar';
|
|
1100
|
+
qux?: 'baz';
|
|
1101
|
+
};
|
|
1102
|
+
|
|
1103
|
+
type ExampleWithoutIndexSignatures = OmitIndexSignature<Example>;
|
|
1104
|
+
//=> {foo: 'bar'; qux?: 'baz'}
|
|
1105
|
+
```
|
|
1106
|
+
|
|
1107
|
+
@see {@link PickIndexSignature}
|
|
1108
|
+
@category Object
|
|
1109
|
+
*/
|
|
1110
|
+
type OmitIndexSignature<ObjectType> = { [KeyType in keyof ObjectType as {} extends Record<KeyType, unknown> ? never : KeyType]: ObjectType[KeyType] };
|
|
1111
|
+
//#endregion
|
|
1112
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/pick-index-signature.d.ts
|
|
1113
|
+
/**
|
|
1114
|
+
Pick only index signatures from the given object type, leaving out all explicitly defined properties.
|
|
1115
|
+
|
|
1116
|
+
This is the counterpart of `OmitIndexSignature`.
|
|
1117
|
+
|
|
1118
|
+
@example
|
|
1119
|
+
```
|
|
1120
|
+
import type {PickIndexSignature} from 'type-fest';
|
|
1121
|
+
|
|
1122
|
+
declare const symbolKey: unique symbol;
|
|
1123
|
+
|
|
1124
|
+
type Example = {
|
|
1125
|
+
// These index signatures will remain.
|
|
1126
|
+
[x: string]: unknown;
|
|
1127
|
+
[x: number]: unknown;
|
|
1128
|
+
[x: symbol]: unknown;
|
|
1129
|
+
[x: `head-${string}`]: string;
|
|
1130
|
+
[x: `${string}-tail`]: string;
|
|
1131
|
+
[x: `head-${string}-tail`]: string;
|
|
1132
|
+
[x: `${bigint}`]: string;
|
|
1133
|
+
[x: `embedded-${number}`]: string;
|
|
1134
|
+
|
|
1135
|
+
// These explicitly defined keys will be removed.
|
|
1136
|
+
['kebab-case-key']: string;
|
|
1137
|
+
[symbolKey]: string;
|
|
1138
|
+
foo: 'bar';
|
|
1139
|
+
qux?: 'baz';
|
|
1140
|
+
};
|
|
1141
|
+
|
|
1142
|
+
type ExampleIndexSignature = PickIndexSignature<Example>;
|
|
1143
|
+
// {
|
|
1144
|
+
// [x: string]: unknown;
|
|
1145
|
+
// [x: number]: unknown;
|
|
1146
|
+
// [x: symbol]: unknown;
|
|
1147
|
+
// [x: `head-${string}`]: string;
|
|
1148
|
+
// [x: `${string}-tail`]: string;
|
|
1149
|
+
// [x: `head-${string}-tail`]: string;
|
|
1150
|
+
// [x: `${bigint}`]: string;
|
|
1151
|
+
// [x: `embedded-${number}`]: string;
|
|
1152
|
+
// }
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
@see {@link OmitIndexSignature}
|
|
1156
|
+
@category Object
|
|
1157
|
+
*/
|
|
1158
|
+
type PickIndexSignature<ObjectType> = { [KeyType in keyof ObjectType as {} extends Record<KeyType, unknown> ? KeyType : never]: ObjectType[KeyType] };
|
|
1159
|
+
//#endregion
|
|
1160
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/merge.d.ts
|
|
1161
|
+
// Merges two objects without worrying about index signatures.
|
|
1162
|
+
type SimpleMerge<Destination, Source> = Simplify<{ [Key in keyof Destination as Key extends keyof Source ? never : Key]: Destination[Key] } & Source>;
|
|
1163
|
+
/**
|
|
1164
|
+
Merge two types into a new type. Keys of the second type overrides keys of the first type.
|
|
1165
|
+
|
|
1166
|
+
This is different from the TypeScript `&` (intersection) operator. With `&`, conflicting property types are intersected, which often results in `never`. For example, `{a: string} & {a: number}` makes `a` become `string & number`, which resolves to `never`. With `Merge`, the second type's keys cleanly override the first, so `Merge<{a: string}, {a: number}>` gives `{a: number}` as expected. `Merge` also produces a flattened type (via `Simplify`), making it more readable in IDE tooltips compared to `A & B`.
|
|
1167
|
+
|
|
1168
|
+
@example
|
|
1169
|
+
```
|
|
1170
|
+
import type {Merge} from 'type-fest';
|
|
1171
|
+
|
|
1172
|
+
type Foo = {
|
|
1173
|
+
a: string;
|
|
1174
|
+
b: number;
|
|
1175
|
+
};
|
|
1176
|
+
|
|
1177
|
+
type Bar = {
|
|
1178
|
+
a: number; // Conflicts with Foo['a']
|
|
1179
|
+
c: boolean;
|
|
1180
|
+
};
|
|
1181
|
+
|
|
1182
|
+
// With `&`, `a` becomes `string & number` which is `never`. Not what you want.
|
|
1183
|
+
type WithIntersection = (Foo & Bar)['a'];
|
|
1184
|
+
//=> never
|
|
1185
|
+
|
|
1186
|
+
// With `Merge`, `a` is cleanly overridden to `number`.
|
|
1187
|
+
type WithMerge = Merge<Foo, Bar>['a'];
|
|
1188
|
+
//=> number
|
|
1189
|
+
```
|
|
1190
|
+
|
|
1191
|
+
@example
|
|
1192
|
+
```
|
|
1193
|
+
import type {Merge} from 'type-fest';
|
|
1194
|
+
|
|
1195
|
+
type Foo = {
|
|
1196
|
+
[x: string]: unknown;
|
|
1197
|
+
[x: number]: unknown;
|
|
1198
|
+
foo: string;
|
|
1199
|
+
bar: symbol;
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
type Bar = {
|
|
1203
|
+
[x: number]: number;
|
|
1204
|
+
[x: symbol]: unknown;
|
|
1205
|
+
bar: Date;
|
|
1206
|
+
baz: boolean;
|
|
1207
|
+
};
|
|
1208
|
+
|
|
1209
|
+
export type FooBar = Merge<Foo, Bar>;
|
|
1210
|
+
//=> {
|
|
1211
|
+
// [x: string]: unknown;
|
|
1212
|
+
// [x: number]: number;
|
|
1213
|
+
// [x: symbol]: unknown;
|
|
1214
|
+
// foo: string;
|
|
1215
|
+
// bar: Date;
|
|
1216
|
+
// baz: boolean;
|
|
1217
|
+
// }
|
|
1218
|
+
```
|
|
1219
|
+
|
|
1220
|
+
Note: If you want a merge type that more accurately reflects the runtime behavior of object spread or `Object.assign`, refer to the {@link ObjectMerge} type.
|
|
1221
|
+
|
|
1222
|
+
@see {@link ObjectMerge}
|
|
1223
|
+
@category Object
|
|
1224
|
+
*/
|
|
1225
|
+
type Merge<Destination, Source> = Destination extends unknown // For distributing `Destination`
|
|
1226
|
+
? Source extends unknown // For distributing `Source`
|
|
1227
|
+
? If<IsEqual<Destination, Source>, Destination, _Merge<Destination, Source>> : never // Should never happen
|
|
1228
|
+
: never;
|
|
1229
|
+
// Should never happen
|
|
1230
|
+
type _Merge<Destination, Source> = Simplify<SimpleMerge<PickIndexSignature<Destination>, PickIndexSignature<Source>> & SimpleMerge<OmitIndexSignature<Destination>, OmitIndexSignature<Source>>>;
|
|
1231
|
+
//#endregion
|
|
1232
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/internal/object.d.ts
|
|
1233
|
+
/**
|
|
1234
|
+
Merges user specified options with default options.
|
|
1235
|
+
|
|
1236
|
+
@example
|
|
1237
|
+
```
|
|
1238
|
+
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
|
|
1239
|
+
type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false};
|
|
1240
|
+
type SpecifiedOptions = {leavesOnly: true};
|
|
1241
|
+
|
|
1242
|
+
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
|
|
1243
|
+
//=> {maxRecursionDepth: 10; leavesOnly: true}
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
@example
|
|
1247
|
+
```
|
|
1248
|
+
// Complains if default values are not provided for optional options
|
|
1249
|
+
|
|
1250
|
+
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
|
|
1251
|
+
type DefaultPathsOptions = {maxRecursionDepth: 10};
|
|
1252
|
+
type SpecifiedOptions = {};
|
|
1253
|
+
|
|
1254
|
+
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
|
|
1255
|
+
// ~~~~~~~~~~~~~~~~~~~
|
|
1256
|
+
// Property 'leavesOnly' is missing in type 'DefaultPathsOptions' but required in type '{ maxRecursionDepth: number; leavesOnly: boolean; }'.
|
|
1257
|
+
```
|
|
1258
|
+
|
|
1259
|
+
@example
|
|
1260
|
+
```
|
|
1261
|
+
// Complains if an option's default type does not conform to the expected type
|
|
1262
|
+
|
|
1263
|
+
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
|
|
1264
|
+
type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: 'no'};
|
|
1265
|
+
type SpecifiedOptions = {};
|
|
1266
|
+
|
|
1267
|
+
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
|
|
1268
|
+
// ~~~~~~~~~~~~~~~~~~~
|
|
1269
|
+
// Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'.
|
|
1270
|
+
```
|
|
1271
|
+
|
|
1272
|
+
@example
|
|
1273
|
+
```
|
|
1274
|
+
// Complains if an option's specified type does not conform to the expected type
|
|
1275
|
+
|
|
1276
|
+
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
|
|
1277
|
+
type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false};
|
|
1278
|
+
type SpecifiedOptions = {leavesOnly: 'yes'};
|
|
1279
|
+
|
|
1280
|
+
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
|
|
1281
|
+
// ~~~~~~~~~~~~~~~~
|
|
1282
|
+
// Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'.
|
|
1283
|
+
```
|
|
1284
|
+
*/
|
|
1285
|
+
type ApplyDefaultOptions<Options extends object, Defaults extends Simplify<Omit<Required<Options>, RequiredKeysOf<Options>> & Partial<Record<RequiredKeysOf<Options>, never>>>, SpecifiedOptions extends Options> = _ApplyDefaultOptions<Options, Defaults, SpecifiedOptions> extends infer Result extends Required<Options> // `extends Required<Options>` ensures that `ApplyDefaultOptions<SomeOption, ...>` is always assignable to `Required<SomeOption>`
|
|
1286
|
+
? Result : never;
|
|
1287
|
+
type _ApplyDefaultOptions<Options, Defaults, SpecifiedOptions> = If<IsAny<SpecifiedOptions>, Defaults, If<IsNever<SpecifiedOptions>, Defaults, Merge<Defaults, { [Key in keyof SpecifiedOptions as undefined extends Required<Options>[Key & keyof Options] ? Key : undefined extends SpecifiedOptions[Key] ? never : Key]: SpecifiedOptions[Key] }>>>;
|
|
1288
|
+
/**
|
|
1289
|
+
Collapses literal types in a union into their corresponding primitive types, when possible. For example, `CollapseLiterals<'foo' | 'bar' | (string & {})>` returns `string`.
|
|
1290
|
+
|
|
1291
|
+
Note: This doesn't collapse literals within tagged types. For example, `CollapseLiterals<Tagged<'foo' | (string & {}), 'Tag'>>` returns `("foo" & Tag<"Tag", never>) | (string & Tag<"Tag", never>)` and not `string & Tag<"Tag", never>`.
|
|
1292
|
+
|
|
1293
|
+
Use-case: For collapsing unions created using {@link LiteralUnion}.
|
|
1294
|
+
|
|
1295
|
+
@example
|
|
1296
|
+
```
|
|
1297
|
+
import type {LiteralUnion} from 'type-fest';
|
|
1298
|
+
|
|
1299
|
+
type A = CollapseLiterals<'foo' | 'bar' | (string & {})>;
|
|
1300
|
+
//=> string
|
|
1301
|
+
|
|
1302
|
+
type B = CollapseLiterals<LiteralUnion<1 | 2 | 3, number>>;
|
|
1303
|
+
//=> number
|
|
1304
|
+
|
|
1305
|
+
type C = CollapseLiterals<LiteralUnion<'onClick' | 'onChange', `on${string}`>>;
|
|
1306
|
+
//=> `on${string}`
|
|
1307
|
+
|
|
1308
|
+
type D = CollapseLiterals<'click' | 'change' | (`on${string}` & {})>;
|
|
1309
|
+
//=> 'click' | 'change' | `on${string}`
|
|
1310
|
+
|
|
1311
|
+
type E = CollapseLiterals<LiteralUnion<'foo' | 'bar', string> | null | undefined>;
|
|
1312
|
+
//=> string | null | undefined
|
|
1313
|
+
```
|
|
1314
|
+
*/
|
|
1315
|
+
type CollapseLiterals<T> = {} extends T ? T : T extends infer U & {} ? U : T;
|
|
1316
|
+
//#endregion
|
|
1317
|
+
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/partial-on-undefined-deep.d.ts
|
|
1318
|
+
/**
|
|
1319
|
+
@see {@link PartialOnUndefinedDeep}
|
|
1320
|
+
*/
|
|
1321
|
+
type PartialOnUndefinedDeepOptions = {
|
|
1322
|
+
/**
|
|
1323
|
+
Whether to affect the individual elements of arrays and tuples.
|
|
1324
|
+
@default false
|
|
1325
|
+
*/
|
|
1326
|
+
readonly recurseIntoArrays?: boolean;
|
|
1327
|
+
};
|
|
1328
|
+
type DefaultPartialOnUndefinedDeepOptions = {
|
|
1329
|
+
recurseIntoArrays: false;
|
|
1330
|
+
};
|
|
1331
|
+
/**
|
|
1332
|
+
Create a deep version of another type where all keys accepting `undefined` type are set to optional.
|
|
1333
|
+
|
|
1334
|
+
This utility type is recursive, transforming at any level deep. By default, it does not affect arrays and tuples items unless you explicitly pass `{recurseIntoArrays: true}` as the second type argument.
|
|
1335
|
+
|
|
1336
|
+
Use-cases:
|
|
1337
|
+
- Make all properties of a type that can be undefined optional to not have to specify keys with undefined value.
|
|
1338
|
+
|
|
1339
|
+
@example
|
|
1340
|
+
```
|
|
1341
|
+
import type {PartialOnUndefinedDeep} from 'type-fest';
|
|
1342
|
+
|
|
1343
|
+
type Settings = {
|
|
1344
|
+
optionA: string;
|
|
1345
|
+
optionB: number | undefined;
|
|
1346
|
+
subOption: {
|
|
1347
|
+
subOptionA: boolean;
|
|
1348
|
+
subOptionB: boolean | undefined;
|
|
1349
|
+
};
|
|
1350
|
+
};
|
|
1351
|
+
|
|
1352
|
+
const testSettings: PartialOnUndefinedDeep<Settings> = {
|
|
1353
|
+
optionA: 'foo',
|
|
1354
|
+
// 👉 optionB is now optional and can be omitted
|
|
1355
|
+
subOption: {
|
|
1356
|
+
subOptionA: true,
|
|
1357
|
+
// 👉 subOptionB is now optional as well and can be omitted
|
|
1358
|
+
},
|
|
1359
|
+
};
|
|
1360
|
+
```
|
|
1361
|
+
|
|
1362
|
+
@category Object
|
|
1363
|
+
*/
|
|
1364
|
+
type PartialOnUndefinedDeep<T, Options extends PartialOnUndefinedDeepOptions = {}> = _PartialOnUndefinedDeep<T, ApplyDefaultOptions<PartialOnUndefinedDeepOptions, DefaultPartialOnUndefinedDeepOptions, Options>>;
|
|
1365
|
+
type _PartialOnUndefinedDeep<T, Options extends Required<PartialOnUndefinedDeepOptions>> = T extends Record<any, any> | undefined ? { [KeyType in keyof T as undefined extends T[KeyType] ? If<IsUnknown<T[KeyType]>, never, KeyType> : never]?: PartialOnUndefinedDeepValue<T[KeyType], Options> } extends infer U // Make a partial type with all value types accepting undefined (and set them optional)
|
|
1366
|
+
? Merge<{ [KeyType in keyof T as KeyType extends LiteralKeyOf<U> ? never : KeyType]: PartialOnUndefinedDeepValue<T[KeyType], Options> }, U> // Join all remaining keys not treated in U
|
|
1367
|
+
: never // Should not happen
|
|
1368
|
+
: T;
|
|
1369
|
+
/**
|
|
1370
|
+
Utility type to get the value type by key and recursively call `PartialOnUndefinedDeep` to transform sub-objects.
|
|
1371
|
+
*/
|
|
1372
|
+
type PartialOnUndefinedDeepValue<T, Options extends Required<PartialOnUndefinedDeepOptions>> = T extends BuiltIns | ((...arguments_: any[]) => unknown) ? T : T extends ReadonlyArray<infer U> // Test if type is array or tuple
|
|
1373
|
+
? Options['recurseIntoArrays'] extends true // Check if option is activated
|
|
1374
|
+
? U[] extends T // Check if array not tuple
|
|
1375
|
+
? readonly U[] extends T ? ReadonlyArray<_PartialOnUndefinedDeep<U, Options>> // Readonly array treatment
|
|
1376
|
+
: Array<_PartialOnUndefinedDeep<U, Options>> // Mutable array treatment
|
|
1377
|
+
: _PartialOnUndefinedDeep<{ [Key in keyof T]: _PartialOnUndefinedDeep<T[Key], Options> }, Options> // Tuple treatment
|
|
1378
|
+
: T : T extends Record<any, any> | undefined ? _PartialOnUndefinedDeep<T, Options> : unknown;
|
|
1379
|
+
//#endregion
|
|
1380
|
+
//#region src/types.d.ts
|
|
1381
|
+
interface BasicModel<T> {
|
|
1382
|
+
title?: string;
|
|
1383
|
+
description?: string;
|
|
1384
|
+
examples?: T[];
|
|
1385
|
+
schema?: StandardTypedV1<T, T>;
|
|
1386
|
+
}
|
|
1387
|
+
interface Int32Model extends BasicModel<number> {
|
|
1388
|
+
kind: "int32";
|
|
1389
|
+
}
|
|
1390
|
+
interface Float32Model extends BasicModel<number> {
|
|
1391
|
+
kind: "float32";
|
|
1392
|
+
}
|
|
1393
|
+
interface Float64Model extends BasicModel<number> {
|
|
1394
|
+
kind: "float64";
|
|
1395
|
+
}
|
|
1396
|
+
interface BooleanModel extends BasicModel<boolean> {
|
|
1397
|
+
kind: "boolean";
|
|
1398
|
+
}
|
|
1399
|
+
interface StringModel extends BasicModel<string> {
|
|
1400
|
+
kind: "string";
|
|
1401
|
+
}
|
|
1402
|
+
interface ArrayModel<T extends Models> extends BasicModel<InferModel<T>[]> {
|
|
1403
|
+
kind: "array";
|
|
1404
|
+
base: T;
|
|
1405
|
+
}
|
|
1406
|
+
interface SetModel<T extends Models> extends BasicModel<Set<InferModel<T>>> {
|
|
1407
|
+
kind: "set";
|
|
1408
|
+
base: T;
|
|
1409
|
+
}
|
|
1410
|
+
interface MapModel<T extends Models> extends BasicModel<Map<string, InferModel<T>>> {
|
|
1411
|
+
kind: "map";
|
|
1412
|
+
base: T;
|
|
1413
|
+
}
|
|
1414
|
+
interface RecordModel<T extends Record<string, Models>, R extends keyof T & string> extends BasicModel<PropertiesType<T, R>> {
|
|
1415
|
+
kind: "record";
|
|
1416
|
+
properties: T;
|
|
1417
|
+
required: R[];
|
|
1418
|
+
id: string;
|
|
1419
|
+
}
|
|
1420
|
+
type PropertiesType<T extends Record<string, Models>, R extends keyof T> = PartialOnUndefinedDeep<{ [key in keyof T]: key extends R ? InferModel<T[key]> : InferModel<T[key]> | undefined }>;
|
|
1421
|
+
interface UnionModel<T extends Record<string, Models>> extends BasicModel<InferUnion<T>> {
|
|
1422
|
+
kind: "union";
|
|
1423
|
+
variants: T;
|
|
1424
|
+
id: string;
|
|
1425
|
+
}
|
|
1426
|
+
type InferUnion<T extends Record<string, Models>> = { [key in keyof T]: { [k in key]: StandardTypedV1.InferOutput<NonNullable<T[key]["schema"]>> } }[keyof T];
|
|
1427
|
+
interface TaggedUnionModel<K extends string, D extends string, V extends Record<string, Models>> extends BasicModel<InferTaggedUnion<K, D, V>> {
|
|
1428
|
+
kind: "taggedUnion";
|
|
1429
|
+
variants: V;
|
|
1430
|
+
variantKey: K;
|
|
1431
|
+
payloadKey: D;
|
|
1432
|
+
id: string;
|
|
1433
|
+
}
|
|
1434
|
+
interface TaggedUnionModelOptions<K extends string, D extends string, V extends Record<string, Models>> extends Omit<TaggedUnionModel<K, D, V>, "kind"> {}
|
|
1435
|
+
type InferTaggedUnion<K extends string, D extends string, V extends Record<string, Models>> = { [key in keyof V]: { [k in K | D]: k extends K ? key : k extends D ? StandardTypedV1.InferOutput<NonNullable<V[key]["schema"]>> : never } }[keyof V];
|
|
1436
|
+
interface LiteralModel<T extends string | number | boolean> extends BasicModel<T> {
|
|
1437
|
+
kind: "literal";
|
|
1438
|
+
value: T;
|
|
1439
|
+
}
|
|
1440
|
+
interface NullModel extends BasicModel<undefined | null> {
|
|
1441
|
+
kind: "null";
|
|
1442
|
+
}
|
|
1443
|
+
type OptionsOf<T extends Models> = Omit<T, "kind">;
|
|
1444
|
+
interface EnumsModel<T extends {
|
|
1445
|
+
[key: string]: string;
|
|
1446
|
+
}> extends BasicModel<T[keyof T]> {
|
|
1447
|
+
kind: "enums";
|
|
1448
|
+
id: string;
|
|
1449
|
+
variants: T;
|
|
1450
|
+
}
|
|
1451
|
+
interface DatetimeModel extends BasicModel<string> {
|
|
1452
|
+
kind: "datetime";
|
|
1453
|
+
}
|
|
1454
|
+
interface DateModel extends BasicModel<string> {
|
|
1455
|
+
kind: "date";
|
|
1456
|
+
}
|
|
1457
|
+
interface DurationModel extends BasicModel<string> {
|
|
1458
|
+
kind: "duration";
|
|
1459
|
+
}
|
|
1460
|
+
type Models = Int32Model | Float32Model | Float64Model | BooleanModel | StringModel | ArrayModel<any> | SetModel<any> | MapModel<any> | RecordModel<Record<string, Models>, string> | UnionModel<Record<string, Models>> | TaggedUnionModel<string, string, Record<string, Models>> | LiteralModel<string | number | boolean> | NullModel | EnumsModel<{
|
|
1461
|
+
[key: string]: string;
|
|
1462
|
+
}> | DatetimeModel | DateModel | DurationModel;
|
|
1463
|
+
type InferModel<T> = T extends {
|
|
1464
|
+
schema?: StandardTypedV1<unknown, unknown>;
|
|
1465
|
+
} ? StandardTypedV1.InferOutput<NonNullable<T["schema"]>> : never;
|
|
1466
|
+
declare function int32(options?: OptionsOf<Int32Model>): Int32Model;
|
|
1467
|
+
declare function float32(options?: OptionsOf<Float32Model>): Float32Model;
|
|
1468
|
+
declare function float64(options?: OptionsOf<Float64Model>): Float64Model;
|
|
1469
|
+
declare function boolean(options?: OptionsOf<BooleanModel>): BooleanModel;
|
|
1470
|
+
declare function string(options?: OptionsOf<StringModel>): StringModel;
|
|
1471
|
+
declare function array<T extends Models>(options: OptionsOf<ArrayModel<T>>): ArrayModel<T>;
|
|
1472
|
+
declare function set<T extends Models>(options: OptionsOf<SetModel<T>>): SetModel<T>;
|
|
1473
|
+
declare function map<T extends Models>(options: OptionsOf<MapModel<T>>): MapModel<T>;
|
|
1474
|
+
declare function record<T extends Record<string, Models>, R extends keyof T & string>(options: OptionsOf<RecordModel<T, R>>): RecordModel<T, R>;
|
|
1475
|
+
declare function union<T extends Record<string, Models>>(options: OptionsOf<UnionModel<T>>): UnionModel<T>;
|
|
1476
|
+
declare function taggedUnion<K extends string, D extends string, V extends Record<string, Models>>(options: TaggedUnionModelOptions<K, D, V>): TaggedUnionModel<K, D, V>;
|
|
1477
|
+
declare function literal<const T extends string | boolean | number>(value: T): LiteralModel<T>;
|
|
1478
|
+
declare function nullLike(): NullModel;
|
|
1479
|
+
interface EnumsModelOptions<T extends {
|
|
1480
|
+
[key: string]: string;
|
|
1481
|
+
}> extends Omit<EnumsModel<T>, "kind"> {}
|
|
1482
|
+
declare function enums<const T extends {
|
|
1483
|
+
[key: string]: string;
|
|
1484
|
+
}>(options: EnumsModelOptions<T>): EnumsModel<T>;
|
|
1485
|
+
interface DatetimeModelOptions extends Omit<DatetimeModel, "kind"> {}
|
|
1486
|
+
declare function datetime(options?: DatetimeModelOptions): DatetimeModel;
|
|
1487
|
+
interface DateModelOptions extends Omit<DateModel, "kind"> {}
|
|
1488
|
+
declare function date(options?: DateModelOptions): DateModel;
|
|
1489
|
+
interface DurationModelOptions extends Omit<DurationModel, "kind"> {}
|
|
1490
|
+
declare function duration(options?: DurationModelOptions): DurationModel;
|
|
1491
|
+
//#endregion
|
|
1492
|
+
//#region src/utils/index.d.ts
|
|
1493
|
+
type ExtractPathParams<Path extends string> = string extends Path ? string : Path extends `${infer _Start}/{${infer Param}}/${infer Rest}` ? Param | ExtractPathParams<`/${Rest}`> : Path extends `${infer _Start}/{${infer Param}}` ? Param : never;
|
|
1494
|
+
//#endregion
|
|
1495
|
+
//#region src/api.d.ts
|
|
1496
|
+
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD" | "TRACE";
|
|
1497
|
+
type SimpleType = Int32Model | Float32Model | Float64Model | StringModel | BooleanModel | DatetimeModel | DateModel | DurationModel;
|
|
1498
|
+
interface RouterModel {
|
|
1499
|
+
basePath?: string;
|
|
1500
|
+
name: string;
|
|
1501
|
+
routes: Record<string, RouteModel<string, Record<string, SimpleType>, Models, RecordModel<Record<string, Models>, string>, RecordModel<Record<string, Models>, string>, Record<number, ResponseModel<Models, RecordModel<Record<string, Models>, string>>>>>;
|
|
1502
|
+
}
|
|
1503
|
+
interface RouteModel<Path extends string, Variables extends Record<string, SimpleType>, Body extends Models, Queries extends RecordModel<Record<string, Models>, string>, Headers extends RecordModel<Record<string, Models>, string>, Responses extends Record<number, ResponseModel<Models, RecordModel<Record<string, Models>, string>>>> {
|
|
1504
|
+
kind: "route";
|
|
1505
|
+
method: HttpMethod;
|
|
1506
|
+
contentType?: string;
|
|
1507
|
+
summary?: string;
|
|
1508
|
+
description?: string;
|
|
1509
|
+
path: Path;
|
|
1510
|
+
variables?: Variables;
|
|
1511
|
+
body?: Body;
|
|
1512
|
+
headers?: Headers;
|
|
1513
|
+
queries?: Queries;
|
|
1514
|
+
responses: Responses;
|
|
1515
|
+
tags?: string[];
|
|
1516
|
+
}
|
|
1517
|
+
type ResponseModel<Body extends Models, Headers extends RecordModel<Record<string, Models>, string>> = JsonResponseModel<Body, Headers> | StreamResponseModel<Body, Headers> | SSEResponseModel<Body, Headers> | BinaryResponseModel<Headers>;
|
|
1518
|
+
interface JsonResponseModel<Body extends Models, Headers extends RecordModel<Record<string, Models>, string>> {
|
|
1519
|
+
kind: "json-response";
|
|
1520
|
+
contentType?: PlainTextLikeContentType | JsonLikeContentType;
|
|
1521
|
+
summary?: string;
|
|
1522
|
+
body?: Body;
|
|
1523
|
+
headers?: Headers;
|
|
1524
|
+
}
|
|
1525
|
+
interface StreamResponseModel<Body extends Models, Headers extends RecordModel<Record<string, Models>, string>> {
|
|
1526
|
+
kind: "stream-response";
|
|
1527
|
+
contentType?: JsonStreamLikeContentType;
|
|
1528
|
+
summary?: string;
|
|
1529
|
+
body?: Body;
|
|
1530
|
+
headers?: Headers;
|
|
1531
|
+
}
|
|
1532
|
+
interface SSEResponseModel<Body extends Models, Headers extends RecordModel<Record<string, Models>, string>> {
|
|
1533
|
+
kind: "sse-response";
|
|
1534
|
+
contentType?: PlainTextStreamLikeContentType;
|
|
1535
|
+
summary?: string;
|
|
1536
|
+
body?: Body;
|
|
1537
|
+
headers?: Headers;
|
|
1538
|
+
}
|
|
1539
|
+
interface BinaryResponseModel<Headers extends RecordModel<Record<string, Models>, string>> {
|
|
1540
|
+
kind: "binary";
|
|
1541
|
+
contentType?: BinaryLikeContentType;
|
|
1542
|
+
summary?: string;
|
|
1543
|
+
headers?: Headers;
|
|
1544
|
+
}
|
|
1545
|
+
interface RouteOptions<Path extends string, Variables extends Record<ExtractPathParams<Path>, SimpleType>, Body extends Models, Queries extends RecordModel<Record<string, Models>, string>, Headers extends RecordModel<Record<string, Models>, string>, Responses extends Record<string, ResponseModel<Models, RecordModel<Record<string, Models>, string>>>> extends Omit<RouteModel<string, Variables, Body, Queries, Headers, Responses>, "kind"> {}
|
|
1546
|
+
declare function route<Path extends string, Variables extends Record<ExtractPathParams<Path>, SimpleType>, Body extends Models, Queries extends RecordModel<Record<string, Models>, string>, Headers extends RecordModel<Record<string, Models>, string>, Responses extends Record<string, ResponseModel<Models, RecordModel<Record<string, Models>, string>>>>(options: RouteOptions<Path, Variables, Body, Queries, Headers, Responses>): RouteModel<Path, Variables, Body, Queries, Headers, Responses>;
|
|
1547
|
+
interface ResponseOptions<Body extends Models, Headers extends RecordModel<Record<string, Models>, string>> {
|
|
1548
|
+
contentType?: string;
|
|
1549
|
+
summary?: string;
|
|
1550
|
+
body?: Body;
|
|
1551
|
+
headers?: Headers;
|
|
1552
|
+
}
|
|
1553
|
+
declare function json<Body extends Models, Headers extends RecordModel<Record<string, Models>, string>>(options: ResponseOptions<Body, Headers>): JsonResponseModel<Body, Headers>;
|
|
1554
|
+
declare function jsonStream<Body extends Models, Headers extends RecordModel<Record<string, Models>, string>>(options: ResponseOptions<Body, Headers>): StreamResponseModel<Body, Headers>;
|
|
1555
|
+
declare function sseStream<Body extends Models, Headers extends RecordModel<Record<string, Models>, string>>(options: ResponseOptions<Body, Headers>): SSEResponseModel<Body, Headers>;
|
|
1556
|
+
interface BinaryResponseOptions<Headers extends RecordModel<Record<string, Models>, string>> {
|
|
1557
|
+
contentType?: BinaryLikeContentType;
|
|
1558
|
+
summary?: string;
|
|
1559
|
+
headers?: Headers;
|
|
1560
|
+
}
|
|
1561
|
+
declare function binary<Headers extends RecordModel<Record<string, Models>, string>>(options: BinaryResponseOptions<Headers>): BinaryResponseModel<Headers>;
|
|
1562
|
+
type PlainTextLikeContentType = (string & {}) | "text/plain" | "text/html" | "text/css" | "text/xml" | "text/markdown" | "text/csv";
|
|
1563
|
+
type JsonLikeContentType = (string & {}) | "application/json" | "application/json; charset=utf-8" | "application/ld+json" | "application/hal+json" | "application/vnd.api+json" | "application/problem+json" | "application/schema+json";
|
|
1564
|
+
type PlainTextStreamLikeContentType = (string & {}) | "text/event-stream";
|
|
1565
|
+
type JsonStreamLikeContentType = (string & {}) | "application/ndjson" | "application/x-ndjson" | "application/jsonl" | "application/json-seq" | "application/stream+json";
|
|
1566
|
+
type BinaryLikeContentType = (string & {}) | "application/octet-stream" | "application/pdf" | "application/zip" | "application/gzip" | "image/jpeg" | "image/png" | "image/gif" | "image/webp" | "image/svg+xml" | "audio/mpeg" | "audio/wav" | "video/mp4" | "video/webm";
|
|
1567
|
+
type FormLikeContentType = (string & {}) | "application/x-www-form-urlencoded" | "multipart/form-data";
|
|
1568
|
+
//#endregion
|
|
1569
|
+
//#region src/security.d.ts
|
|
1570
|
+
interface SecurityPolicyModel {
|
|
1571
|
+
name: string;
|
|
1572
|
+
/** key就是path的模式, 支持正则表达 */
|
|
1573
|
+
paths: Record<string, SecurityPolicyPathItem>;
|
|
1574
|
+
}
|
|
1575
|
+
interface SecurityPolicyPathItem {
|
|
1576
|
+
/** 如果没有设置, 则默认对所有http method生效 */
|
|
1577
|
+
methods?: HttpMethod[];
|
|
1578
|
+
/** 如果没有设置, 则忽略该规则 */
|
|
1579
|
+
pipeline?: SecurityApply[];
|
|
1580
|
+
}
|
|
1581
|
+
type SecurityComponent = ApikeySecurityComponent | OpenIdSecurityComponent;
|
|
1582
|
+
interface ApikeySecurityComponent {
|
|
1583
|
+
kind: "apikey";
|
|
1584
|
+
id: string;
|
|
1585
|
+
name: string;
|
|
1586
|
+
description?: string;
|
|
1587
|
+
}
|
|
1588
|
+
interface OpenIdSecurityComponent {
|
|
1589
|
+
kind: "openIdConnect";
|
|
1590
|
+
id: string;
|
|
1591
|
+
description?: string;
|
|
1592
|
+
scopes: string[];
|
|
1593
|
+
}
|
|
1594
|
+
interface SecurityApply {
|
|
1595
|
+
component: SecurityComponent;
|
|
1596
|
+
scopes: string[];
|
|
1597
|
+
}
|
|
1598
|
+
interface SecurityAppliable {
|
|
1599
|
+
apply: (...scopes: string[]) => SecurityApply;
|
|
1600
|
+
}
|
|
1601
|
+
interface ApikeySecurityComponentOptions {
|
|
1602
|
+
id: string;
|
|
1603
|
+
name: string;
|
|
1604
|
+
description?: string;
|
|
1605
|
+
}
|
|
1606
|
+
declare function apikey(options: ApikeySecurityComponentOptions): ApikeySecurityComponent & SecurityAppliable;
|
|
1607
|
+
interface OpenIdComponentOptions {
|
|
1608
|
+
id: string;
|
|
1609
|
+
description?: string;
|
|
1610
|
+
scopes: string[];
|
|
1611
|
+
}
|
|
1612
|
+
declare function openIdConnect(options: OpenIdComponentOptions): OpenIdSecurityComponent & SecurityAppliable;
|
|
1613
|
+
//#endregion
|
|
1614
|
+
//#region src/deployment.d.ts
|
|
1615
|
+
interface OpenIdDeployment {
|
|
1616
|
+
kind: "openIdConnectDeployment";
|
|
1617
|
+
component: OpenIdSecurityComponent;
|
|
1618
|
+
issuer: string;
|
|
1619
|
+
}
|
|
1620
|
+
interface OpenIdDeploymentOptions {
|
|
1621
|
+
component: OpenIdSecurityComponent;
|
|
1622
|
+
issuer: string;
|
|
1623
|
+
}
|
|
1624
|
+
declare function deployOpenIdConnect(options: OpenIdDeploymentOptions): OpenIdDeployment;
|
|
1625
|
+
type SecurityDeployment = OpenIdDeployment;
|
|
61
1626
|
//#endregion
|
|
62
1627
|
//#region src/schemas/json-schema-draft-2020-12.d.ts
|
|
63
1628
|
interface JsonSchemaObject extends JsonSchemaCore, JsonSchemaApplicator, JsonSchemaUnevaluated, JsonSchemaValidation, JsonSchemaMetaData, JsonSchemaFormat, JsonSchemaContent {}
|
|
@@ -105,7 +1670,7 @@ interface JsonSchemaUnevaluated {
|
|
|
105
1670
|
unevaluatedProperties?: JsonSchema;
|
|
106
1671
|
}
|
|
107
1672
|
interface JsonSchemaValidation {
|
|
108
|
-
type?: SimpleType | SimpleType[];
|
|
1673
|
+
type?: SimpleType$1 | SimpleType$1[];
|
|
109
1674
|
const?: any;
|
|
110
1675
|
enum?: any[];
|
|
111
1676
|
multipleOf?: number;
|
|
@@ -147,280 +1712,31 @@ interface JsonSchemaContent {
|
|
|
147
1712
|
contentSchema?: JsonSchema;
|
|
148
1713
|
}
|
|
149
1714
|
declare const SimpleTypes: readonly ["array", "boolean", "integer", "null", "number", "object", "string"];
|
|
150
|
-
type SimpleType = (typeof SimpleTypes)[number];
|
|
151
|
-
//#endregion
|
|
152
|
-
//#region src/schemas/schema-variants.d.ts
|
|
153
|
-
interface StringSchema {
|
|
154
|
-
maxLength?: number;
|
|
155
|
-
minLength?: number;
|
|
156
|
-
pattern?: string;
|
|
157
|
-
format?: FormatVariants | (string & {});
|
|
158
|
-
}
|
|
159
|
-
interface NumberSchema {
|
|
160
|
-
multipleOf?: number;
|
|
161
|
-
maximum?: number;
|
|
162
|
-
exclusiveMaximum?: number;
|
|
163
|
-
minimum?: number;
|
|
164
|
-
exclusiveMinimum?: number;
|
|
165
|
-
}
|
|
166
|
-
interface ArraySchema {
|
|
167
|
-
maxItems?: number;
|
|
168
|
-
minItems?: number;
|
|
169
|
-
contains?: JsonSchemaObject;
|
|
170
|
-
maxContains?: number;
|
|
171
|
-
minContains?: number;
|
|
172
|
-
}
|
|
173
|
-
interface SetSchema {
|
|
174
|
-
maxItems?: number;
|
|
175
|
-
minItems?: number;
|
|
176
|
-
contains?: JsonSchemaObject;
|
|
177
|
-
maxContains?: number;
|
|
178
|
-
minContains?: number;
|
|
179
|
-
}
|
|
180
|
-
interface MapSchema {
|
|
181
|
-
maxProperties?: number;
|
|
182
|
-
minProperties?: number;
|
|
183
|
-
required?: string[];
|
|
184
|
-
dependentRequired?: {
|
|
185
|
-
[key: string]: string[];
|
|
186
|
-
};
|
|
187
|
-
}
|
|
1715
|
+
type SimpleType$1 = (typeof SimpleTypes)[number];
|
|
188
1716
|
//#endregion
|
|
189
|
-
//#region src/
|
|
190
|
-
interface
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
declare function
|
|
204
|
-
|
|
205
|
-
kind: "int64";
|
|
206
|
-
schema?: StringSchema;
|
|
207
|
-
}
|
|
208
|
-
interface Int64ModelOptions extends Omit<Int64Model, "kind"> {}
|
|
209
|
-
declare function int64(options?: Int64ModelOptions): Int64Model;
|
|
210
|
-
interface Float32Model extends BasicModel<number> {
|
|
211
|
-
kind: "float32";
|
|
212
|
-
schema?: NumberSchema;
|
|
213
|
-
}
|
|
214
|
-
interface Float32ModelOptions extends Omit<Float32Model, "kind"> {}
|
|
215
|
-
declare function float32(options?: Float32ModelOptions): Float32Model;
|
|
216
|
-
interface Float64Model extends BasicModel<number> {
|
|
217
|
-
kind: "float64";
|
|
218
|
-
schema?: NumberSchema;
|
|
219
|
-
}
|
|
220
|
-
interface Float64ModelOptions extends Omit<Float64Model, "kind"> {}
|
|
221
|
-
declare function float64(options?: Float64ModelOptions): Float64Model;
|
|
222
|
-
interface BooleanModel extends BasicModel<boolean> {
|
|
223
|
-
kind: "boolean";
|
|
224
|
-
}
|
|
225
|
-
interface BooleanModelOptions extends Omit<BooleanModel, "kind"> {}
|
|
226
|
-
declare function boolean(options?: BooleanModelOptions): BooleanModel;
|
|
227
|
-
interface StringModel extends BasicModel<string> {
|
|
228
|
-
kind: "string";
|
|
229
|
-
schema?: StringSchema;
|
|
230
|
-
}
|
|
231
|
-
interface StringModelOptions extends Omit<StringModel, "kind"> {}
|
|
232
|
-
declare function string(options?: StringModelOptions): StringModel;
|
|
233
|
-
interface LiteralModel<T extends string | number | boolean> extends BasicModel<T> {
|
|
234
|
-
kind: "literal";
|
|
235
|
-
value: T;
|
|
236
|
-
}
|
|
237
|
-
interface LiteralModelOptions<T extends string | number | boolean> extends Omit<LiteralModel<T>, "kind"> {}
|
|
238
|
-
declare function literal<const T extends string | number | boolean>(options: LiteralModelOptions<T>): LiteralModel<T>;
|
|
239
|
-
/**
|
|
240
|
-
* 表示一个可选类型,代表"值可能存在也可能不存在"的语义。
|
|
241
|
-
*
|
|
242
|
-
* 设计理念:
|
|
243
|
-
* - 统一"空白"语义:将 `null`、`undefined` 和缺失值等多种"空"的概念合并为单一语义,
|
|
244
|
-
* 避免类型系统中存在多个含义模糊的"空"状态。
|
|
245
|
-
* - 序列化到 JSON 时,`Optional` 可以表示为 `null` 或完全省略(取决于上下文)。
|
|
246
|
-
* `InferModelJsonType<T> | null | undefined` 表示该值可以是基础类型、`null` 或 `undefined`。
|
|
247
|
-
* - 如果需要区分"显式设置为空"和"从未设置"等细分语义,应当另行设计专用类型。
|
|
248
|
-
*
|
|
249
|
-
* @template T 基础模型类型
|
|
250
|
-
*/
|
|
251
|
-
interface OptionalModel<T extends TypeModels> extends BasicModel<InferModelJsonType<T> | null | undefined> {
|
|
252
|
-
kind: "optional";
|
|
253
|
-
base: T;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* 将类型模型转换为可选类型。
|
|
257
|
-
*
|
|
258
|
-
* @template T 基础模型类型
|
|
259
|
-
*/
|
|
260
|
-
type Optionalize<T extends TypeModels> = T extends TypeModels ? OptionalModel<T> : never;
|
|
261
|
-
interface OptionalModelOptions<T extends TypeModels> extends Omit<OptionalModel<T>, "kind" | "base"> {}
|
|
262
|
-
/**
|
|
263
|
-
* 创建一个可选类型模型。
|
|
264
|
-
*
|
|
265
|
-
* @param base 基础模型类型
|
|
266
|
-
* @param options 可选配置选项
|
|
267
|
-
* @returns 可选类型模型
|
|
268
|
-
*/
|
|
269
|
-
declare function optional<T extends TypeModels>(base: T, options?: OptionalModelOptions<T>): OptionalModel<T>;
|
|
270
|
-
interface ArrayModel<T> extends BasicModel<InferModelJsonType<T>[]> {
|
|
271
|
-
kind: "array";
|
|
272
|
-
base: T;
|
|
273
|
-
schema?: ArraySchema;
|
|
274
|
-
}
|
|
275
|
-
interface ArrayModelOptions<T extends TypeModels> extends Omit<ArrayModel<T>, "kind" | "base"> {}
|
|
276
|
-
declare function array<T extends TypeModels>(base: T, options?: ArrayModelOptions<T>): ArrayModel<T>;
|
|
277
|
-
interface SetModel<T extends TypeModels> extends BasicModel<InferModelJsonType<T>[]> {
|
|
278
|
-
kind: "set";
|
|
279
|
-
base: T;
|
|
280
|
-
schema?: SetSchema;
|
|
281
|
-
}
|
|
282
|
-
interface SetModelOptions<T extends TypeModels> extends Omit<SetModel<T>, "kind" | "base"> {}
|
|
283
|
-
declare function set<T extends TypeModels>(base: T, options?: SetModelOptions<T>): SetModel<T>;
|
|
284
|
-
interface MapModel<T> extends BasicModel<{
|
|
285
|
-
[key: string]: InferModelJsonType<T>;
|
|
286
|
-
}> {
|
|
287
|
-
kind: "map";
|
|
288
|
-
base: T;
|
|
289
|
-
schema?: MapSchema;
|
|
290
|
-
}
|
|
291
|
-
interface MapModelOptions<T extends TypeModels> extends Omit<MapModel<T>, "kind" | "base"> {}
|
|
292
|
-
declare function map<T extends TypeModels>(base: T, options?: MapModelOptions<T>): MapModel<T>;
|
|
293
|
-
interface RecordModel<T extends {
|
|
294
|
-
[key: string]: TypeModels;
|
|
295
|
-
}> extends BasicModel<InferRecordJsonType<T>> {
|
|
296
|
-
kind: "record";
|
|
297
|
-
id: string;
|
|
298
|
-
properties: T;
|
|
299
|
-
}
|
|
300
|
-
type KeyOfOptional<T extends {
|
|
301
|
-
[key: string]: TypeModels;
|
|
302
|
-
}> = { [key in keyof T]: T[key] extends OptionalModel<any> ? key : never }[keyof T];
|
|
303
|
-
type InferRecordJsonType<T extends {
|
|
304
|
-
[key: string]: TypeModels;
|
|
305
|
-
}, O extends KeyOfOptional<T> = KeyOfOptional<T>> = Simplify<{ [key in Exclude<keyof T, O>]: InferModelJsonType<T[key]> } & { [key in O]?: InferModelJsonType<T[key]> }>;
|
|
306
|
-
interface RecordModelOptions<T extends {
|
|
307
|
-
[key: string]: TypeModels;
|
|
308
|
-
}> extends Omit<RecordModel<T>, "kind"> {}
|
|
309
|
-
declare function record<const T extends {
|
|
310
|
-
[key: string]: TypeModels;
|
|
311
|
-
}>(options: RecordModelOptions<T>): RecordModel<T>;
|
|
312
|
-
interface UnionModel<T extends {
|
|
313
|
-
[key: string]: TypeModels;
|
|
314
|
-
}> extends BasicModel<InferUnionJsonType<T>> {
|
|
315
|
-
kind: "union";
|
|
316
|
-
id: string;
|
|
317
|
-
variants: T;
|
|
318
|
-
}
|
|
319
|
-
type InferUnionJsonType<T extends {
|
|
320
|
-
[key: string]: TypeModels;
|
|
321
|
-
}> = { [key in keyof T]: { [k in key]: InferModelJsonType<T[key]> } }[keyof T];
|
|
322
|
-
interface UnionModelOptions<T extends {
|
|
323
|
-
[key: string]: TypeModels;
|
|
324
|
-
}> extends Omit<UnionModel<T>, "kind"> {}
|
|
325
|
-
declare function union<const T extends {
|
|
326
|
-
[key: string]: TypeModels;
|
|
327
|
-
}>(options: UnionModelOptions<T>): UnionModel<T>;
|
|
328
|
-
interface DatetimeModel extends BasicModel<string> {
|
|
329
|
-
kind: "datetime";
|
|
330
|
-
schema?: StringSchema;
|
|
331
|
-
}
|
|
332
|
-
interface DatetimeModelOptions extends Omit<DatetimeModel, "kind"> {}
|
|
333
|
-
declare function datetime(options?: DatetimeModelOptions): DatetimeModel;
|
|
334
|
-
interface DateModel extends BasicModel<string> {
|
|
335
|
-
kind: "date";
|
|
336
|
-
schema?: StringSchema;
|
|
337
|
-
}
|
|
338
|
-
interface DateModelOptions extends Omit<DateModel, "kind"> {}
|
|
339
|
-
declare function date(options?: DateModelOptions): DateModel;
|
|
340
|
-
interface DurationModel extends BasicModel<string> {
|
|
341
|
-
kind: "duration";
|
|
342
|
-
schema?: StringSchema;
|
|
343
|
-
}
|
|
344
|
-
interface DurationModelOptions extends Omit<DurationModel, "kind"> {}
|
|
345
|
-
declare function duration(options?: DurationModelOptions): DurationModel;
|
|
346
|
-
interface ErrorModel<Code extends string, Context extends {
|
|
347
|
-
[key: string]: TypeModels;
|
|
348
|
-
}> extends BasicModel<InferErrorModel<Code, Context>> {
|
|
349
|
-
kind: "error";
|
|
350
|
-
id: string;
|
|
351
|
-
code: Code;
|
|
352
|
-
context: Context;
|
|
353
|
-
}
|
|
354
|
-
type InferErrorModel<Code extends string, Context extends {
|
|
355
|
-
[key: string]: TypeModels;
|
|
356
|
-
}> = {
|
|
357
|
-
code: Code;
|
|
358
|
-
context: InferRecordJsonType<Context>;
|
|
359
|
-
};
|
|
360
|
-
interface ErrorModelOptions<Code extends string, Context extends {
|
|
361
|
-
[key: string]: TypeModels;
|
|
362
|
-
}> extends Omit<ErrorModel<Code, Context>, "kind"> {}
|
|
363
|
-
declare function error<const Code extends string, Context extends {
|
|
364
|
-
[key: string]: TypeModels;
|
|
365
|
-
}>(options: ErrorModelOptions<Code, Context>): ErrorModel<Code, Context>;
|
|
366
|
-
interface EnumsModel<T extends {
|
|
367
|
-
[key: string]: string;
|
|
368
|
-
}> extends BasicModel<T[keyof T]> {
|
|
1717
|
+
//#region src/generate-jsonschema.d.ts
|
|
1718
|
+
interface SchemaRegistry {
|
|
1719
|
+
getRef: (model: Models) => string | undefined;
|
|
1720
|
+
add: (id: string, model: Models) => SchemaRegistry;
|
|
1721
|
+
}
|
|
1722
|
+
interface GenerateJsonSchemaOptions {
|
|
1723
|
+
model: Models;
|
|
1724
|
+
registry?: SchemaRegistry;
|
|
1725
|
+
toJsonSchema?: (type?: StandardTypedV1) => JsonSchemaObject;
|
|
1726
|
+
}
|
|
1727
|
+
interface GenerateJsonSchemaResult {
|
|
1728
|
+
jsonSchema: JsonSchema;
|
|
1729
|
+
registry: SchemaRegistry;
|
|
1730
|
+
}
|
|
1731
|
+
declare function generateJsonSchema(options: GenerateJsonSchemaOptions): GenerateJsonSchemaResult;
|
|
1732
|
+
declare function createJsonSchemaRegistry(models?: Map<Models, {
|
|
369
1733
|
id: string;
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
interface EnumsModelOptions<T extends {
|
|
374
|
-
[key: string]: string;
|
|
375
|
-
}> extends Omit<EnumsModel<T>, "kind"> {}
|
|
376
|
-
declare function enums<const T extends {
|
|
377
|
-
[key: string]: string;
|
|
378
|
-
}>(options: EnumsModelOptions<T>): EnumsModel<T>;
|
|
379
|
-
interface TaggedUnionModel<Tag extends string, Variants extends {
|
|
380
|
-
[key: string]: RecordModel<{ [key in Tag]: LiteralModel<string> }>;
|
|
381
|
-
}> extends BasicModel<InferTaggedUnionJsonType<Tag, Variants>> {
|
|
1734
|
+
schema: JsonSchema;
|
|
1735
|
+
}>): SchemaRegistry;
|
|
1736
|
+
declare function createOpenapiSchemaRegistry(models?: Map<Models, {
|
|
382
1737
|
id: string;
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
variants: Variants;
|
|
386
|
-
}
|
|
387
|
-
type InferTaggedUnionJsonType<Tag extends string, Variants extends {
|
|
388
|
-
[key: string]: RecordModel<{ [key in Tag]: LiteralModel<string> }>;
|
|
389
|
-
}> = { [key in keyof Variants]: Variants[key] extends RecordModel<infer R> ? InferRecordJsonType<R> : never }[keyof Variants];
|
|
390
|
-
interface TaggedUnionModelOptions<Tag extends string, Variants extends {
|
|
391
|
-
[key: string]: RecordModel<{ [key in Tag]: LiteralModel<string> }>;
|
|
392
|
-
}> extends Omit<TaggedUnionModel<Tag, Variants>, "kind"> {}
|
|
393
|
-
declare function taggedUnion<const Tag extends string, Variants extends {
|
|
394
|
-
[key: string]: RecordModel<{ [key in Tag]: LiteralModel<string> }>;
|
|
395
|
-
}>(options: TaggedUnionModelOptions<Tag, Variants>): TaggedUnionModel<Tag, Variants>;
|
|
396
|
-
type TypeModels = Int32Model | Int64Model | Float32Model | Float64Model | BooleanModel | StringModel | LiteralModel<string | number | boolean> | OptionalModel<TypeModels> | ArrayModel<TypeModels> | SetModel<TypeModels> | MapModel<TypeModels> | RecordModel<{
|
|
397
|
-
[key: string]: TypeModels;
|
|
398
|
-
}> | UnionModel<{
|
|
399
|
-
[key: string]: TypeModels;
|
|
400
|
-
}> | TaggedUnionModel<string, {
|
|
401
|
-
[key: string]: any;
|
|
402
|
-
}> | DatetimeModel | DateModel | DurationModel | ErrorModel<string, {
|
|
403
|
-
[key: string]: TypeModels;
|
|
404
|
-
}> | EnumsModel<{
|
|
405
|
-
[key: string]: string;
|
|
406
|
-
}>;
|
|
407
|
-
type InferModelJsonType<T> = any extends T ? never : TypeModels extends T ? any : T extends Int32Model ? number : T extends Int64Model ? string : T extends Float32Model ? number : T extends Float64Model ? number : T extends BooleanModel ? boolean : T extends StringModel ? string : T extends LiteralModel<infer R> ? R : T extends OptionalModel<infer R> ? InferModelJsonType<R> | undefined | null : T extends ArrayModel<infer R> ? InferModelJsonType<R>[] : T extends SetModel<infer R> ? InferModelJsonType<R>[] : T extends MapModel<infer R> ? Record<string, InferModelJsonType<R>> : T extends RecordModel<infer R> ? InferRecordJsonType<R> : T extends UnionModel<infer R> ? InferUnionJsonType<R> : T extends TaggedUnionModel<infer Tag, infer Variants> ? InferTaggedUnionJsonType<Tag, Variants> : T extends DatetimeModel ? string : T extends DateModel ? string : T extends DurationModel ? string : T extends ErrorModel<infer Code, infer Context> ? InferErrorModel<Code, Context> : T extends EnumsModel<infer R> ? R[keyof R] : never;
|
|
408
|
-
interface ModelToJsonSchemaOptions {
|
|
409
|
-
model: TypeModels;
|
|
410
|
-
target?: "draft-2020-12";
|
|
411
|
-
reference?: "inline" | "json-schema" | "openapi";
|
|
412
|
-
depth?: number;
|
|
413
|
-
}
|
|
414
|
-
declare function generateJsonSchema(options: ModelToJsonSchemaOptions): JsonSchemaObject;
|
|
415
|
-
type NamedModel = RecordModel<{
|
|
416
|
-
[key: string]: TypeModels;
|
|
417
|
-
}> | EnumsModel<{
|
|
418
|
-
[key: string]: string;
|
|
419
|
-
}> | UnionModel<{
|
|
420
|
-
[key: string]: TypeModels;
|
|
421
|
-
}> | ErrorModel<string, {
|
|
422
|
-
[key: string]: TypeModels;
|
|
423
|
-
}>;
|
|
1738
|
+
schema: JsonSchema;
|
|
1739
|
+
}>): SchemaRegistry;
|
|
424
1740
|
//#endregion
|
|
425
1741
|
//#region src/schemas/openapi-schema.d.ts
|
|
426
1742
|
interface OpenAPIObject {
|
|
@@ -716,203 +2032,134 @@ interface SecurityRequirementObject {
|
|
|
716
2032
|
[key: string]: string[];
|
|
717
2033
|
}
|
|
718
2034
|
//#endregion
|
|
719
|
-
//#region src/
|
|
720
|
-
type ExtractPathParams<Path extends string> = string extends Path ? string : Path extends `${infer _Start}/{${infer Param}}/${infer Rest}` ? Param | ExtractPathParams<`/${Rest}`> : Path extends `${infer _Start}/{${infer Param}}` ? Param : never;
|
|
721
|
-
//#endregion
|
|
722
|
-
//#region src/type-system/http.d.ts
|
|
723
|
-
type AllowedHttpValue = StringModel | Int32Model | Int64Model | BooleanModel | LiteralModel<string | number | boolean> | Optionalize<StringModel | Int32Model | Int64Model | BooleanModel | LiteralModel<string | number | boolean>>;
|
|
724
|
-
type PartialOf<T extends {
|
|
725
|
-
[key: string]: any;
|
|
726
|
-
}, K extends keyof T> = Simplify<{ [key in Exclude<keyof T, K>]: T[key] } & { [key in K]?: T[key] }>;
|
|
2035
|
+
//#region src/generate-openapi.d.ts
|
|
727
2036
|
interface GenerateOpenapiOptions {
|
|
728
|
-
info:
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
tags?: OpenAPIObject["tags"];
|
|
732
|
-
servers?: OpenAPIObject["servers"];
|
|
733
|
-
}
|
|
734
|
-
declare function generateOpenapi(options: GenerateOpenapiOptions): OpenAPIObject;
|
|
735
|
-
declare function collectModelFromRoutes(routes: HttpRouteModel[]): Map<string, TypeModels>;
|
|
736
|
-
declare function collectModelDeep(model: TypeModels): Map<string, TypeModels>;
|
|
737
|
-
interface HttpResponseModel {
|
|
738
|
-
status: number;
|
|
739
|
-
description?: string;
|
|
740
|
-
content?: HttpContentModel;
|
|
741
|
-
headers?: {
|
|
742
|
-
[key: string]: AllowedHttpValue | OptionalModel<AllowedHttpValue>;
|
|
743
|
-
};
|
|
744
|
-
cookies?: {
|
|
745
|
-
[key: string]: AllowedHttpValue | OptionalModel<AllowedHttpValue>;
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
|
-
interface HttpRouteModel<Path extends string = string> {
|
|
749
|
-
kind: "http-route";
|
|
750
|
-
id: string;
|
|
751
|
-
path: Path;
|
|
752
|
-
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD" | "TRACE";
|
|
753
|
-
description?: string;
|
|
754
|
-
summary?: string;
|
|
755
|
-
variables: { [key in ExtractPathParams<Path>]: AllowedHttpValue };
|
|
756
|
-
queries?: {
|
|
757
|
-
[key: string]: AllowedHttpValue | OptionalModel<AllowedHttpValue>;
|
|
758
|
-
};
|
|
759
|
-
cookies?: {
|
|
760
|
-
[key: string]: AllowedHttpValue | OptionalModel<AllowedHttpValue>;
|
|
761
|
-
};
|
|
762
|
-
headers?: {
|
|
763
|
-
[key: string]: AllowedHttpValue | OptionalModel<AllowedHttpValue>;
|
|
764
|
-
};
|
|
765
|
-
content?: HttpContentModel;
|
|
766
|
-
responses?: {
|
|
767
|
-
[key: string]: HttpResponseModel;
|
|
768
|
-
};
|
|
769
|
-
tags?: string[];
|
|
2037
|
+
info: InfoObject;
|
|
2038
|
+
servers?: ServerObject[];
|
|
2039
|
+
routers: RouterModel[];
|
|
770
2040
|
security?: {
|
|
771
|
-
|
|
2041
|
+
policy?: SecurityPolicyModel;
|
|
2042
|
+
deployments?: Record<string, SecurityDeployment>;
|
|
772
2043
|
};
|
|
773
2044
|
}
|
|
774
|
-
interface
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
}
|
|
788
|
-
interface
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
2045
|
+
interface GenerateOpenapiResult {
|
|
2046
|
+
openapi: OpenAPIObject;
|
|
2047
|
+
registry: SchemaRegistry;
|
|
2048
|
+
}
|
|
2049
|
+
declare function generateOpenapi(options: GenerateOpenapiOptions): GenerateOpenapiResult;
|
|
2050
|
+
//#endregion
|
|
2051
|
+
//#region src/codegen/descriptors.d.ts
|
|
2052
|
+
type AnyRouteModel = RouteModel<string, Record<string, SimpleType>, Models, RecordModel<Record<string, Models>, string>, RecordModel<Record<string, Models>, string>, Record<number, any>>;
|
|
2053
|
+
interface CollectOptions {
|
|
2054
|
+
/** 将 originalId 映射为标识符,默认 pascalCase */
|
|
2055
|
+
identifier?: (id: string) => string;
|
|
2056
|
+
/** 命名空间,如 "com.example" */
|
|
2057
|
+
namespace?: string;
|
|
2058
|
+
}
|
|
2059
|
+
interface ModelDescriptor {
|
|
2060
|
+
kind: string;
|
|
2061
|
+
originalId: string;
|
|
2062
|
+
identifier: string;
|
|
2063
|
+
namespace?: string;
|
|
2064
|
+
title?: string;
|
|
794
2065
|
description?: string;
|
|
2066
|
+
deprecated?: boolean;
|
|
2067
|
+
examples?: unknown[];
|
|
2068
|
+
}
|
|
2069
|
+
interface RecordDescriptor extends ModelDescriptor {
|
|
2070
|
+
kind: "record";
|
|
2071
|
+
fields: FieldDescriptor[];
|
|
795
2072
|
}
|
|
796
|
-
interface
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
2073
|
+
interface FieldDescriptor {
|
|
2074
|
+
name: string;
|
|
2075
|
+
model: Models;
|
|
2076
|
+
required: boolean;
|
|
2077
|
+
title?: string;
|
|
801
2078
|
description?: string;
|
|
2079
|
+
deprecated?: boolean;
|
|
802
2080
|
}
|
|
803
|
-
interface
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
kind: "
|
|
809
|
-
|
|
810
|
-
model: RecordModel<T>;
|
|
811
|
-
}
|
|
812
|
-
interface FormContentOptions<T extends {
|
|
813
|
-
[key: string]: AllowedHttpValue;
|
|
814
|
-
}> extends Omit<FormContentModel<T>, "kind"> {}
|
|
815
|
-
declare function form<T extends {
|
|
816
|
-
[key: string]: AllowedHttpValue;
|
|
817
|
-
}>(options: FormContentOptions<T>): FormContentModel<T>;
|
|
818
|
-
type HttpContentModel = PlainTextContentModel | JsonContentModel | JsonStreamContentModel | BinaryStreamContentModel | FormContentModel<{
|
|
819
|
-
[key: string]: AllowedHttpValue;
|
|
820
|
-
}> | ServerSentEventContentModel;
|
|
821
|
-
type PlainTextLikeContentType = (string & {}) | "text/plain" | "text/html" | "text/css" | "text/xml" | "text/markdown" | "text/csv";
|
|
822
|
-
type JsonLikeContentType = (string & {}) | "application/json" | "application/json; charset=utf-8" | "application/ld+json" | "application/hal+json" | "application/vnd.api+json" | "application/problem+json" | "application/schema+json";
|
|
823
|
-
type PlainTextStreamLikeContentType = (string & {}) | "text/event-stream";
|
|
824
|
-
type JsonStreamLikeContentType = (string & {}) | "application/ndjson" | "application/x-ndjson" | "application/jsonl" | "application/json-seq" | "application/stream+json";
|
|
825
|
-
type BinaryLikeContentType = (string & {}) | "application/octet-stream" | "application/pdf" | "application/zip" | "application/gzip" | "image/jpeg" | "image/png" | "image/gif" | "image/webp" | "image/svg+xml" | "audio/mpeg" | "audio/wav" | "video/mp4" | "video/webm";
|
|
826
|
-
type FormLikeContentType = (string & {}) | "application/x-www-form-urlencoded" | "multipart/form-data";
|
|
827
|
-
interface ServerSentEventContentModel {
|
|
828
|
-
kind: "server-sent-event-content";
|
|
829
|
-
type: "text/event-stream";
|
|
830
|
-
model?: TypeModels;
|
|
831
|
-
}
|
|
832
|
-
type ServerSentEventContentOptions = Partial<ServerSentEventContentModel>;
|
|
833
|
-
declare function sse(options?: ServerSentEventContentOptions): ServerSentEventContentModel;
|
|
834
|
-
//#endregion
|
|
835
|
-
//#region src/generator/java.d.ts
|
|
836
|
-
interface GenerateJavaClassOptions {
|
|
837
|
-
package: string;
|
|
838
|
-
model: NamedModel;
|
|
839
|
-
}
|
|
840
|
-
declare function generateJavaClass(options: GenerateJavaClassOptions): string;
|
|
841
|
-
declare function formatJava(code: string): Promise<string>;
|
|
842
|
-
interface GenerateJavaOptions {
|
|
843
|
-
package: string;
|
|
844
|
-
srcDir: string;
|
|
845
|
-
routes?: HttpRouteModel[];
|
|
846
|
-
models?: TypeModels[];
|
|
847
|
-
}
|
|
848
|
-
declare function generateJavaCodes(options: GenerateJavaOptions): Promise<{
|
|
849
|
-
path: string;
|
|
850
|
-
code: string;
|
|
851
|
-
}[]>;
|
|
852
|
-
//#endregion
|
|
853
|
-
//#region src/generator/rust.d.ts
|
|
854
|
-
interface GenerateRustCodeOptions {
|
|
855
|
-
module_name: string;
|
|
856
|
-
model: RecordModel<{
|
|
857
|
-
[key: string]: TypeModels;
|
|
858
|
-
}> | UnionModel<{
|
|
859
|
-
[key: string]: TypeModels;
|
|
860
|
-
}> | EnumsModel<{
|
|
861
|
-
[key: string]: string;
|
|
862
|
-
}> | ErrorModel<string, {
|
|
863
|
-
[key: string]: TypeModels;
|
|
864
|
-
}>;
|
|
2081
|
+
interface EnumsDescriptor extends ModelDescriptor {
|
|
2082
|
+
kind: "enums";
|
|
2083
|
+
values: Record<string, string>;
|
|
2084
|
+
}
|
|
2085
|
+
interface UnionDescriptor extends ModelDescriptor {
|
|
2086
|
+
kind: "union";
|
|
2087
|
+
variants: Record<string, Models>;
|
|
865
2088
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
routes?: HttpRouteModel[];
|
|
872
|
-
models?: TypeModels[];
|
|
2089
|
+
interface TaggedUnionDescriptor extends ModelDescriptor {
|
|
2090
|
+
kind: "taggedUnion";
|
|
2091
|
+
variants: Record<string, Models>;
|
|
2092
|
+
variantKey: string;
|
|
2093
|
+
payloadKey: string;
|
|
873
2094
|
}
|
|
874
|
-
|
|
2095
|
+
type AnyNamedDescriptor = RecordDescriptor | EnumsDescriptor | UnionDescriptor | TaggedUnionDescriptor;
|
|
2096
|
+
interface OperationDescriptor {
|
|
2097
|
+
id: string;
|
|
2098
|
+
group: string;
|
|
2099
|
+
method: HttpMethod;
|
|
875
2100
|
path: string;
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
2101
|
+
summary?: string;
|
|
2102
|
+
description?: string;
|
|
2103
|
+
tags?: string[];
|
|
2104
|
+
requestModel: Models | null;
|
|
2105
|
+
responses: Record<number, Models | null>;
|
|
2106
|
+
responseKinds: Record<number, string>;
|
|
2107
|
+
pathVariables: Record<string, {
|
|
2108
|
+
model: Models;
|
|
2109
|
+
name: string;
|
|
2110
|
+
}>;
|
|
2111
|
+
queries: Record<string, {
|
|
2112
|
+
model: Models;
|
|
2113
|
+
name: string;
|
|
2114
|
+
required: boolean;
|
|
2115
|
+
}>;
|
|
2116
|
+
headers: Record<string, {
|
|
2117
|
+
model: Models;
|
|
2118
|
+
name: string;
|
|
2119
|
+
required: boolean;
|
|
890
2120
|
}>;
|
|
891
|
-
}> = { [key in keyof Variants]: InferDeserialized<Variants[key]> }[keyof Variants];
|
|
892
|
-
type InferDeserializedError<Code extends string, Context extends {
|
|
893
|
-
[key: string]: TypeModels;
|
|
894
|
-
}> = [Context] extends [never] ? {
|
|
895
|
-
code: Code;
|
|
896
|
-
} : {
|
|
897
|
-
code: Code;
|
|
898
|
-
context: InferDeserializedRecord<Context>;
|
|
899
|
-
};
|
|
900
|
-
declare function deserialize<T extends TypeModels>(model: T, json: string): DeserializeResult<InferDeserialized<T>>;
|
|
901
|
-
declare function deserializeInner<T extends TypeModels>(model: T, value: any): DeserializeResult<InferDeserialized<T>>;
|
|
902
|
-
interface DeserializeSuccess<T> {
|
|
903
|
-
isSuccess: true;
|
|
904
|
-
value: T;
|
|
905
2121
|
}
|
|
906
|
-
interface
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
}
|
|
2122
|
+
interface SchemaInfo {
|
|
2123
|
+
kind: "record" | "enums" | "union" | "taggedUnion";
|
|
2124
|
+
fields?: Array<{
|
|
2125
|
+
name: string;
|
|
2126
|
+
model: Models;
|
|
2127
|
+
required: boolean;
|
|
2128
|
+
}>;
|
|
2129
|
+
variants?: Record<string, string>;
|
|
2130
|
+
unionVariants?: Record<string, Models>;
|
|
2131
|
+
variantKey?: string;
|
|
2132
|
+
payloadKey?: string;
|
|
2133
|
+
}
|
|
2134
|
+
type SchemaMap = Map<string, SchemaInfo>;
|
|
2135
|
+
//#endregion
|
|
2136
|
+
//#region src/codegen/collect.d.ts
|
|
2137
|
+
declare function collectNamedModels(models: Models[], options?: CollectOptions): AnyNamedDescriptor[];
|
|
2138
|
+
declare function collectOperations(routers: RouterModel[]): OperationDescriptor[];
|
|
2139
|
+
declare function collectSchemaMap(ops: OperationDescriptor[]): SchemaMap;
|
|
2140
|
+
declare function resolveNamedRoot(m: Models): {
|
|
2141
|
+
id: string;
|
|
2142
|
+
} | null;
|
|
2143
|
+
//#endregion
|
|
2144
|
+
//#region src/codegen/json-schema.d.ts
|
|
2145
|
+
declare function mergeJsonSchemas(schemas: Record<string, Models>): JsonSchemaObject;
|
|
2146
|
+
//#endregion
|
|
2147
|
+
//#region src/codegen/hono-server.d.ts
|
|
2148
|
+
interface HonoServerOptions {
|
|
2149
|
+
routers: RouterModel[];
|
|
2150
|
+
identifier?: (id: string) => string;
|
|
2151
|
+
namespace?: string;
|
|
2152
|
+
configuration?: RecordModel<Record<string, Models>, string>;
|
|
2153
|
+
}
|
|
2154
|
+
declare function generateHonoServer(options: HonoServerOptions): Record<string, string>;
|
|
2155
|
+
//#endregion
|
|
2156
|
+
//#region src/codegen/ts-client.d.ts
|
|
2157
|
+
interface TsClientOptions {
|
|
2158
|
+
routers: RouterModel[];
|
|
2159
|
+
identifier?: (id: string) => string;
|
|
2160
|
+
namespace?: string;
|
|
913
2161
|
}
|
|
914
|
-
|
|
915
|
-
declare function serialize<T extends TypeModels>(model: T, value: InferDeserialized<T>): string;
|
|
2162
|
+
declare function generateTsClient(options: TsClientOptions): Record<string, string>;
|
|
916
2163
|
//#endregion
|
|
917
|
-
export {
|
|
2164
|
+
export { AnyNamedDescriptor, AnyRouteModel, ApikeySecurityComponent, ApikeySecurityComponentOptions, ArrayModel, BasicModel, BinaryLikeContentType, BinaryResponseModel, BinaryResponseOptions, BooleanModel, CollectOptions, DateModel, DateModelOptions, DatetimeModel, DatetimeModelOptions, DurationModel, DurationModelOptions, EnumsDescriptor, EnumsModel, EnumsModelOptions, FieldDescriptor, Float32Model, Float64Model, FormLikeContentType, GenerateJsonSchemaOptions, GenerateJsonSchemaResult, GenerateOpenapiOptions, GenerateOpenapiResult, HonoServerOptions, HttpMethod, InferModel, InferTaggedUnion, InferUnion, Int32Model, JsonLikeContentType, JsonResponseModel, JsonStreamLikeContentType, LiteralModel, MapModel, ModelDescriptor, Models, NullModel, OpenIdComponentOptions, OpenIdDeployment, OpenIdDeploymentOptions, OpenIdSecurityComponent, OperationDescriptor, OptionsOf, PlainTextLikeContentType, PlainTextStreamLikeContentType, PropertiesType, RecordDescriptor, RecordModel, ResponseModel, ResponseOptions, RouteModel, RouteOptions, RouterModel, SSEResponseModel, SchemaInfo, SchemaMap, SchemaRegistry, SecurityAppliable, SecurityApply, SecurityComponent, SecurityDeployment, SecurityPolicyModel, SecurityPolicyPathItem, SetModel, SimpleType, StreamResponseModel, StringModel, TaggedUnionDescriptor, TaggedUnionModel, TsClientOptions, UnionDescriptor, UnionModel, apikey, array, binary, boolean, collectNamedModels, collectOperations, collectSchemaMap, createJsonSchemaRegistry, createOpenapiSchemaRegistry, date, datetime, deployOpenIdConnect, duration, enums, float32, float64, generateHonoServer, generateJsonSchema, generateOpenapi, generateTsClient, int32, json, jsonStream, literal, map, mergeJsonSchemas, nullLike, openIdConnect, record, resolveNamedRoot, route, set, sseStream, string, taggedUnion, union };
|
|
918
2165
|
//# sourceMappingURL=index.d.mts.map
|