kind-adt 0.1.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/COMMERCIAL_LICENSE.md +25 -0
- package/LICENSE +373 -0
- package/README.md +627 -0
- package/index.d.ts +1455 -0
- package/index.js +346 -0
- package/package.json +36 -0
- package/utils.d.ts +57 -0
- package/utils.js +172 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,1455 @@
|
|
|
1
|
+
/******************
|
|
2
|
+
* Main functions *
|
|
3
|
+
******************/
|
|
4
|
+
/**
|
|
5
|
+
* Generate constructors and related functions (e.g., match functions) for an ADT. These include:
|
|
6
|
+
* - `ADT.<Tag>`: Constructor for the ADT.
|
|
7
|
+
* - `ADT.is<Tag>`: Type guard function for the ADT.
|
|
8
|
+
* - `ADT.unwrap`: Deconstructor for the ADT. This function extracts the fields of the ADT into a
|
|
9
|
+
* TypeScript tuple (i.e., an array).
|
|
10
|
+
* - `ADT.unwrap<Tag>`: Deconstructor for the ADT with a specific tag. If the passed ADT has a
|
|
11
|
+
* different tag, it will throw an error.
|
|
12
|
+
* - `ADT.if<Tag>`: Conditional deconstructor for the ADT. Similar to Rust’s `if let` syntax.
|
|
13
|
+
* - `ADT.match`: A match function to pattern match the ADT. This function requires the return type
|
|
14
|
+
* of each case to be the same.
|
|
15
|
+
* - `ADT.matchW`: Same as `ADT.match`, but allows the return type of each case to be different.
|
|
16
|
+
* @param variants The variants of the ADT. If not provided, a proxy object will be returned.
|
|
17
|
+
* @returns
|
|
18
|
+
*
|
|
19
|
+
* @see {@linkcode Data} for details on how to create an ADT.
|
|
20
|
+
*/
|
|
21
|
+
export function make<F extends Tagged | TypeLambda<never, Tagged>>(
|
|
22
|
+
variants?: readonly Instantiate<F>["_tag"][],
|
|
23
|
+
): Instantiate<F> extends infer Type extends Tagged ?
|
|
24
|
+
Spread<
|
|
25
|
+
{ readonly [Tag in Type["_tag"] as Tag]: Constructor<F, Tag> },
|
|
26
|
+
{
|
|
27
|
+
readonly [Tag in Type["_tag"] as `is${Tag}`]: (
|
|
28
|
+
adt: Type,
|
|
29
|
+
) => adt is FilterTagged<Type, Tag>;
|
|
30
|
+
},
|
|
31
|
+
{ readonly unwrap: Deconstructor<Type> },
|
|
32
|
+
{
|
|
33
|
+
readonly [Tag in Type["_tag"] as `unwrap${Tag}`]: Deconstructor<
|
|
34
|
+
FilterTagged<Type, Tag>
|
|
35
|
+
>;
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
readonly [Tag in Type["_tag"] as `if${Tag}`]: ConditionalDeconstructorOf<
|
|
39
|
+
F,
|
|
40
|
+
Tag
|
|
41
|
+
>;
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
readonly match: MatcherOf<F>;
|
|
45
|
+
readonly matchW: MatcherOfW<F>;
|
|
46
|
+
}
|
|
47
|
+
>
|
|
48
|
+
: never;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Extract the fields of an ADT.
|
|
52
|
+
* @param adt The ADT to unwrap.
|
|
53
|
+
* @returns
|
|
54
|
+
*/
|
|
55
|
+
export function unwrap<T extends Tagged>(adt: T): ExtractFields<T>;
|
|
56
|
+
|
|
57
|
+
/**************
|
|
58
|
+
* Main types *
|
|
59
|
+
**************/
|
|
60
|
+
/**
|
|
61
|
+
* A tagged type with a `_tag` property.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* // Create a tagged type
|
|
66
|
+
* type _ = Tagged<"A", [string, number]>;
|
|
67
|
+
* // => { readonly _tag: "A"; readonly _0: string; readonly _1: number }
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* // Extract a variant from an ADT
|
|
73
|
+
* type Option<T> = Data<{
|
|
74
|
+
* Some: [T];
|
|
75
|
+
* None: [];
|
|
76
|
+
* }>;
|
|
77
|
+
* type Some<T> = Extract<Option<T>, Tagged<"Some">>;
|
|
78
|
+
* // ^?: type Some<T> = { readonly _tag: "Some"; readonly _0: T }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export type Tagged<
|
|
82
|
+
Tag extends string = string,
|
|
83
|
+
Fields = readonly unknown[],
|
|
84
|
+
> = Merge<
|
|
85
|
+
{ readonly _tag: Tag },
|
|
86
|
+
(
|
|
87
|
+
[
|
|
88
|
+
Exclude<keyof Fields, "__labels">,
|
|
89
|
+
IsNever<Exclude<keyof Fields, "__labels">>,
|
|
90
|
+
] extends [number, false] ?
|
|
91
|
+
Exclude<Fields, "__labels">
|
|
92
|
+
: Fields
|
|
93
|
+
) extends infer Fields ?
|
|
94
|
+
{ readonly [I in IndexOf<Fields> as `_${I}`]: Fields[I] }
|
|
95
|
+
: never
|
|
96
|
+
>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create an ADT with tagged types.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* import { type Data, type Tagged, make } from "kind-adt";
|
|
104
|
+
* import type { Arg0, HKT } from "hkt-core";
|
|
105
|
+
*
|
|
106
|
+
* // A Simple ADT
|
|
107
|
+
* export type Option<T> = Data<{
|
|
108
|
+
* // ^?: { readonly _tag: "Some"; readonly _0: T } | { readonly _tag: "None" }
|
|
109
|
+
* Some: [T];
|
|
110
|
+
* None: [];
|
|
111
|
+
* }>;
|
|
112
|
+
* // Extract a variant from an ADT
|
|
113
|
+
* export type Some<T> = Extract<Option<T>, Tagged<"Some">>;
|
|
114
|
+
* // ^?: type Some<T> = { readonly _tag: "Some"; readonly _0: T }
|
|
115
|
+
* // Generate constructors and match functions for the ADT
|
|
116
|
+
* export const Option = make<OptionHKT>();
|
|
117
|
+
* interface OptionHKT extends HKT { // <- Lift the ADT to HKT
|
|
118
|
+
* return: Option<Arg0<this>>;
|
|
119
|
+
* }
|
|
120
|
+
* // Use the ADT
|
|
121
|
+
* function safeDiv(n1: number, n2: number) {
|
|
122
|
+
* // ^?: (n1: number, n2: number) => Option<number>
|
|
123
|
+
* if (n2 === 0) return Option.None;
|
|
124
|
+
* return Option.Some(n1 / n2);
|
|
125
|
+
* }
|
|
126
|
+
* const result = Option.match(safeDiv(1, 2), {
|
|
127
|
+
* // ^?: string
|
|
128
|
+
* Some: (n) => `Result: ${n}`,
|
|
129
|
+
* None: () => {
|
|
130
|
+
* throw new Error("Division by zero");
|
|
131
|
+
* },
|
|
132
|
+
* });
|
|
133
|
+
* console.log(result); // Result: 0.5
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* import { type Data, make } from "kind-adt";
|
|
139
|
+
* import type { Arg0, Arg1, HKT2 } from "hkt-core";
|
|
140
|
+
*
|
|
141
|
+
* // You can add optional labels to the constructor to improve readability of type information
|
|
142
|
+
* export type Result<T, E> = Data<{
|
|
143
|
+
* Ok: [value: T]; // <- With labels
|
|
144
|
+
* Err: [error: E]; // <- With labels
|
|
145
|
+
* }>;
|
|
146
|
+
* export const Result = make<ResultHKT>();
|
|
147
|
+
* interface ResultHKT extends HKT2 {
|
|
148
|
+
* return: Result<Arg0<this>, Arg1<this>>;
|
|
149
|
+
* }
|
|
150
|
+
*
|
|
151
|
+
* // When you hover over `Result.Err`, you will a much more readable type information:
|
|
152
|
+
* Result.Err("Oops!");
|
|
153
|
+
* // ^?: <never, string>(error: string) => Result<never, string>
|
|
154
|
+
* // Without labels, the type information will be less readable:
|
|
155
|
+
* // Result.Err("Oops!");
|
|
156
|
+
* // ^?: <never, string>(args_0: string) => Result<never, string>
|
|
157
|
+
*
|
|
158
|
+
* // This also applies to the generated `ADT.match` function:
|
|
159
|
+
* Result.match(Result.Err("Oops!"), {
|
|
160
|
+
* Ok: (v) => `Value: ${v}`,
|
|
161
|
+
* // ^?: (value: never) => string
|
|
162
|
+
* // Without labels, you get `(args_0: never) => string`
|
|
163
|
+
* Err: (e) => `Error: ${e}`,
|
|
164
|
+
* // ^?: (error: string) => string
|
|
165
|
+
* // Without labels, you get `(args_0: string) => string`
|
|
166
|
+
* });
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* import { type Data, make } from "kind-adt";
|
|
172
|
+
* import type { Arg0, Arg1, HKT2 } from "hkt-core";
|
|
173
|
+
*
|
|
174
|
+
* // Constraints on type parameters are also supported
|
|
175
|
+
* export type Entry<K extends string | number, V> = Data<{
|
|
176
|
+
* Entry: [key: K, value: V];
|
|
177
|
+
* }>;
|
|
178
|
+
* export const { Entry } = make<EntryHKT>();
|
|
179
|
+
* interface EntryHKT extends HKT2<string | number, unknown> {
|
|
180
|
+
* return: Entry<Arg0<this>, Arg1<this>>;
|
|
181
|
+
* }
|
|
182
|
+
*
|
|
183
|
+
* // TypeScript will issue an error if you pass the wrong type of arguments to the constructor:
|
|
184
|
+
* Entry(null, "John");
|
|
185
|
+
* // ~~~~
|
|
186
|
+
* // Argument of type 'null' is not assignable to parameter of type 'string | number'.
|
|
187
|
+
* ```
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* import { type Data, make } from "kind-adt";
|
|
192
|
+
* import type { Arg0, HKT } from "hkt-core";
|
|
193
|
+
*
|
|
194
|
+
* // A sugared syntax for ADTs with only one object argument
|
|
195
|
+
* export type Tree<T> = Data<{
|
|
196
|
+
* Empty: {};
|
|
197
|
+
* Node: { value: T; left: Tree<T>; right: Tree<T> };
|
|
198
|
+
* }>;
|
|
199
|
+
* // This expands to:
|
|
200
|
+
* // type Tree<T> =
|
|
201
|
+
* // | { readonly _tag: "Empty" }
|
|
202
|
+
* // | { readonly _tag: "Node"; readonly _0: { value: T; left: Tree<T>; right: Tree<T> } };
|
|
203
|
+
* // NOTE: kind-adt will treat `{}` as `[]` in this syntax.
|
|
204
|
+
*
|
|
205
|
+
* export const { Empty, Node, match: matchTree } = make<TreeHKT>();
|
|
206
|
+
* interface TreeHKT extends HKT {
|
|
207
|
+
* return: Tree<Arg0<this>>;
|
|
208
|
+
* }
|
|
209
|
+
*
|
|
210
|
+
* const depth: <T>(tree: Tree<T>) => number = matchTree({
|
|
211
|
+
* Empty: () => 0,
|
|
212
|
+
* Node: ({ left, right }) => 1 + Math.max(depth(left), depth(right)),
|
|
213
|
+
* });
|
|
214
|
+
*
|
|
215
|
+
* console.log(depth(Node(1, Node(2, Node(3, Empty, Empty), Empty))); // 3
|
|
216
|
+
* ```
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* import { type Data, make } from "kind-adt";
|
|
221
|
+
* import type { Arg0, HKT } from "hkt-core";
|
|
222
|
+
*
|
|
223
|
+
* // TypeScript sometimes has trouble handling recursive ADTs
|
|
224
|
+
* type Tree<T> = Data<{
|
|
225
|
+
* // ~~~~
|
|
226
|
+
* // Type alias 'Tree' circularly references itself.
|
|
227
|
+
* Empty: [];
|
|
228
|
+
* Node: [value: T, left: Tree<T>, right: Tree<T>];
|
|
229
|
+
* }>;
|
|
230
|
+
*
|
|
231
|
+
* // You might wonder why TypeScript handles the recursive ADT in the previous example correctly,
|
|
232
|
+
* // but fails in this example. The reason is that TypeScript lazily evaluates certain types,
|
|
233
|
+
* // including interfaces, object literal types and function return types, but eagerly evaluates
|
|
234
|
+
* // the rest (e.g., tuple types and type aliases defined by `type`).
|
|
235
|
+
* // In the previous example, we quoted the `Tree` type inside an object literal type, which is
|
|
236
|
+
* // lazily evaluated.
|
|
237
|
+
* // However, in this example, we quote `Tree<T>` in a tuple type, which is eagerly evaluated.
|
|
238
|
+
*
|
|
239
|
+
* // kind-adt provides an alternative syntax for such cases:
|
|
240
|
+
* type Tree<T> = Data<{
|
|
241
|
+
* Empty: [];
|
|
242
|
+
* Node: { 0: T; 1: Tree<T>; 2: Tree<T> };
|
|
243
|
+
* }>;
|
|
244
|
+
* // Instead of using a tuple type, we use an object type with only numeric keys.
|
|
245
|
+
* // This expands to:
|
|
246
|
+
* // type Tree<T> =
|
|
247
|
+
* // | { readonly _tag: "Empty" }
|
|
248
|
+
* // | { readonly _tag: "Node"; readonly _0: T; readonly _1: Tree<T>; readonly _2: Tree<T> };
|
|
249
|
+
* // NOTE: kind-adt treats object with only numeric keys as tuple types, instead of the syntax
|
|
250
|
+
* // sugar for ADTs with only one object argument.
|
|
251
|
+
*
|
|
252
|
+
* // However, such syntax does not support labels. kind-adt also provides a special syntax for
|
|
253
|
+
* // recursive ADTs with labels:
|
|
254
|
+
* type Tree<T> = Data<{
|
|
255
|
+
* Empty: [];
|
|
256
|
+
* Node: {
|
|
257
|
+
* // The `__labels` property can be a labeled tuple containing any type, we only use the labels
|
|
258
|
+
* __labels: [value: void, left: void, right: void];
|
|
259
|
+
* 0: T;
|
|
260
|
+
* 1: Tree<T>;
|
|
261
|
+
* 2: Tree<T>;
|
|
262
|
+
* };
|
|
263
|
+
* }>;
|
|
264
|
+
* // This expands to the same type as the previous example.
|
|
265
|
+
*
|
|
266
|
+
* export const Tree = make<TreeHKT>();
|
|
267
|
+
* interface TreeHKT extends HKT {
|
|
268
|
+
* return: Tree<Arg0<this>>;
|
|
269
|
+
* }
|
|
270
|
+
*
|
|
271
|
+
* const depth: <T>(tree: Tree<T>) => number = Tree.match({
|
|
272
|
+
* Empty: () => 0,
|
|
273
|
+
* Node: (_, left, right) => 1 + Math.max(depth(left), depth(right)),
|
|
274
|
+
* // ^?: (value: T, left: Tree<T>, right: Tree<T>) => number
|
|
275
|
+
* // Labels are preserved in the match function
|
|
276
|
+
* });
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
export type Data<Variants extends Record<string, unknown>> = ValueOf<{
|
|
280
|
+
[Tag in keyof Variants & string]: Variants[Tag] extends (
|
|
281
|
+
readonly unknown[] // Regular ADTs
|
|
282
|
+
) ?
|
|
283
|
+
Tagged<Tag, Variants[Tag]>
|
|
284
|
+
: // Special syntax for recursive ADTs
|
|
285
|
+
[
|
|
286
|
+
Exclude<keyof Variants[Tag], "__labels">,
|
|
287
|
+
IsNever<Exclude<keyof Variants[Tag], "__labels">>,
|
|
288
|
+
] extends [number, false] ?
|
|
289
|
+
Tagged<Tag, Variants[Tag]>
|
|
290
|
+
: // If the object is `{}`, we still treat it as `[]`
|
|
291
|
+
IsNever<keyof Variants[Tag]> extends true ? Tagged<Tag, []>
|
|
292
|
+
: // Special syntax for ADTs with only one object argument
|
|
293
|
+
Tagged<Tag, [fields: Variants[Tag]]>;
|
|
294
|
+
}>;
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* A constructor for an ADT.
|
|
298
|
+
*/
|
|
299
|
+
export type Constructor<
|
|
300
|
+
Type extends Tagged | TypeLambda<never, Tagged>,
|
|
301
|
+
Tag extends string,
|
|
302
|
+
> =
|
|
303
|
+
[Type] extends (
|
|
304
|
+
[Tagged] // Non-generic ADT
|
|
305
|
+
) ?
|
|
306
|
+
{ readonly _tag: Tag } & ((
|
|
307
|
+
...args: ExtractFields<Extract<Type, Tagged<Tag>>>
|
|
308
|
+
) => Type)
|
|
309
|
+
: // Generic ADT
|
|
310
|
+
Type extends TypeLambda<[never], unknown> ?
|
|
311
|
+
unknown extends _UpperBound<HKTParams<Type>[0]> ?
|
|
312
|
+
{ readonly _tag: Tag } & (<T = never>(
|
|
313
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T]>, Tag>>
|
|
314
|
+
) => ApplyHKT<Type, [T]>)
|
|
315
|
+
: { readonly _tag: Tag } & (<
|
|
316
|
+
T extends _UpperBound<HKTParams<Type>[0]> = never,
|
|
317
|
+
>(
|
|
318
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T]>, Tag>>
|
|
319
|
+
) => ApplyHKT<Type, [T]>)
|
|
320
|
+
: Type extends TypeLambda<[never, never], unknown> ?
|
|
321
|
+
[unknown, unknown] extends (
|
|
322
|
+
[_UpperBound<HKTParams<Type>[0]>, _UpperBound<HKTParams<Type>[1]>]
|
|
323
|
+
) ?
|
|
324
|
+
{ readonly _tag: Tag } & (<T = never, U = never>(
|
|
325
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
|
|
326
|
+
) => ApplyHKT<Type, [T, U]>)
|
|
327
|
+
: unknown extends _UpperBound<HKTParams<Type>[0]> ?
|
|
328
|
+
{ readonly _tag: Tag } & (<
|
|
329
|
+
T = never,
|
|
330
|
+
U extends _UpperBound<HKTParams<Type>[1]> = never,
|
|
331
|
+
>(
|
|
332
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
|
|
333
|
+
) => ApplyHKT<Type, [T, U]>)
|
|
334
|
+
: unknown extends _UpperBound<HKTParams<Type>[1]> ?
|
|
335
|
+
{ readonly _tag: Tag } & (<
|
|
336
|
+
T extends _UpperBound<HKTParams<Type>[0]> = never,
|
|
337
|
+
U = never,
|
|
338
|
+
>(
|
|
339
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
|
|
340
|
+
) => ApplyHKT<Type, [T, U]>)
|
|
341
|
+
: { readonly _tag: Tag } & (<
|
|
342
|
+
T extends _UpperBound<HKTParams<Type>[0]> = never,
|
|
343
|
+
U extends _UpperBound<HKTParams<Type>[1]> = never,
|
|
344
|
+
>(
|
|
345
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
|
|
346
|
+
) => ApplyHKT<Type, [T, U]>)
|
|
347
|
+
: Type extends TypeLambda<[never, never, never], unknown> ?
|
|
348
|
+
{ readonly _tag: Tag } & (<
|
|
349
|
+
T extends _UpperBound<HKTParams<Type>[0]> = never,
|
|
350
|
+
U extends _UpperBound<HKTParams<Type>[1]> = never,
|
|
351
|
+
V extends _UpperBound<HKTParams<Type>[2]> = never,
|
|
352
|
+
>(
|
|
353
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U, V]>, Tag>>
|
|
354
|
+
) => ApplyHKT<Type, [T, U, V]>)
|
|
355
|
+
: Type extends TypeLambda<[never, never, never, never], unknown> ?
|
|
356
|
+
{ readonly _tag: Tag } & (<
|
|
357
|
+
T extends _UpperBound<HKTParams<Type>[0]> = never,
|
|
358
|
+
U extends _UpperBound<HKTParams<Type>[1]> = never,
|
|
359
|
+
V extends _UpperBound<HKTParams<Type>[2]> = never,
|
|
360
|
+
W extends _UpperBound<HKTParams<Type>[3]> = never,
|
|
361
|
+
>(
|
|
362
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U, V, W]>, Tag>>
|
|
363
|
+
) => ApplyHKT<Type, [T, U, V, W]>)
|
|
364
|
+
: Type extends TypeLambda<[never, never, never, never, never], unknown> ?
|
|
365
|
+
{ readonly _tag: Tag } & (<
|
|
366
|
+
T extends _UpperBound<HKTParams<Type>[0]> = never,
|
|
367
|
+
U extends _UpperBound<HKTParams<Type>[1]> = never,
|
|
368
|
+
V extends _UpperBound<HKTParams<Type>[2]> = never,
|
|
369
|
+
W extends _UpperBound<HKTParams<Type>[3]> = never,
|
|
370
|
+
X extends _UpperBound<HKTParams<Type>[4]> = never,
|
|
371
|
+
>(
|
|
372
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U, V, W, X]>, Tag>>
|
|
373
|
+
) => ApplyHKT<Type, [T, U, V, W, X]>)
|
|
374
|
+
: Type extends (
|
|
375
|
+
TypeLambda<[never, never, never, never, never, never], unknown>
|
|
376
|
+
) ?
|
|
377
|
+
{ readonly _tag: Tag } & (<
|
|
378
|
+
T extends _UpperBound<HKTParams<Type>[0]> = never,
|
|
379
|
+
U extends _UpperBound<HKTParams<Type>[1]> = never,
|
|
380
|
+
V extends _UpperBound<HKTParams<Type>[2]> = never,
|
|
381
|
+
W extends _UpperBound<HKTParams<Type>[3]> = never,
|
|
382
|
+
X extends _UpperBound<HKTParams<Type>[4]> = never,
|
|
383
|
+
Y extends _UpperBound<HKTParams<Type>[5]> = never,
|
|
384
|
+
>(
|
|
385
|
+
...args: ExtractFields<
|
|
386
|
+
FilterTagged<ApplyHKT<Type, [T, U, V, W, X, Y]>, Tag>
|
|
387
|
+
>
|
|
388
|
+
) => ApplyHKT<Type, [T, U, V, W, X, Y]>)
|
|
389
|
+
: /* support up to 6 type parameters */ never;
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* A type guard function for an ADT.
|
|
393
|
+
*/
|
|
394
|
+
export type Guard<T extends Tagged, Tag extends string> = (
|
|
395
|
+
adt: T,
|
|
396
|
+
) => adt is FilterTagged<T, Tag>;
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* A deconstructor for an ADT.
|
|
400
|
+
*/
|
|
401
|
+
export type Deconstructor<Type extends Tagged> = <T extends Type>(
|
|
402
|
+
adt: T,
|
|
403
|
+
) => ExtractFields<T>;
|
|
404
|
+
|
|
405
|
+
type ConditionalDeconstructorOf<
|
|
406
|
+
F extends Tagged | TypeLambda<never, Tagged>,
|
|
407
|
+
Tag extends string,
|
|
408
|
+
> =
|
|
409
|
+
[F] extends [Tagged] ?
|
|
410
|
+
<R1, R2 = void>(
|
|
411
|
+
adt: F,
|
|
412
|
+
onMatch: (...args: ExtractFields<FilterTagged<F, Tag>>) => R1,
|
|
413
|
+
otherwise?: (adt: Exclude<F, Tagged<Tag>>) => R2,
|
|
414
|
+
) => R1 | R2
|
|
415
|
+
: [F] extends [TypeLambda<[never], Tagged>] ?
|
|
416
|
+
ConditionalDeconstructor1<F, Tag>
|
|
417
|
+
: [F] extends [TypeLambda<[never, never], Tagged>] ?
|
|
418
|
+
ConditionalDeconstructor2<F, Tag>
|
|
419
|
+
: ConditionalDeconstructor<Instantiate<F>, Tag>;
|
|
420
|
+
|
|
421
|
+
type ConditionalDeconstructor1<
|
|
422
|
+
F extends TypeLambda<[never], Tagged>,
|
|
423
|
+
Tag extends string,
|
|
424
|
+
> =
|
|
425
|
+
[unknown] extends HKTParams<F> ?
|
|
426
|
+
<T, R1, R2 = void>(
|
|
427
|
+
adt: ApplyHKT<F, [T]>,
|
|
428
|
+
onMatch: (
|
|
429
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
430
|
+
) => R1,
|
|
431
|
+
otherwise?: (adt: Exclude<ApplyHKT<F, [T]>, Tagged<Tag>>) => R2,
|
|
432
|
+
) => R1 | R2
|
|
433
|
+
: <T extends HKTParams<F>[0], R1, R2 = void>(
|
|
434
|
+
adt: ApplyHKT<F, [T]>,
|
|
435
|
+
onMatch: (
|
|
436
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
437
|
+
) => R1,
|
|
438
|
+
otherwise?: (adt: Exclude<ApplyHKT<F, [T]>, Tagged<Tag>>) => R2,
|
|
439
|
+
) => R1 | R2;
|
|
440
|
+
|
|
441
|
+
type ConditionalDeconstructor2<
|
|
442
|
+
F extends TypeLambda<[never, never], Tagged>,
|
|
443
|
+
Tag extends string,
|
|
444
|
+
> =
|
|
445
|
+
[unknown, unknown] extends HKTParams<F> ?
|
|
446
|
+
<T, U, R1, R2 = void>(
|
|
447
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
448
|
+
onMatch: (
|
|
449
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
450
|
+
) => R1,
|
|
451
|
+
otherwise?: (adt: Exclude<ApplyHKT<F, [T, U]>, Tagged<Tag>>) => R2,
|
|
452
|
+
) => R1 | R2
|
|
453
|
+
: unknown extends HKTParams<F>[0] ?
|
|
454
|
+
<T, U extends HKTParams<F>[1], R1, R2 = void>(
|
|
455
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
456
|
+
onMatch: (
|
|
457
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
458
|
+
) => R1,
|
|
459
|
+
otherwise?: (adt: Exclude<ApplyHKT<F, [T, U]>, Tagged<Tag>>) => R2,
|
|
460
|
+
) => R1 | R2
|
|
461
|
+
: unknown extends HKTParams<F>[1] ?
|
|
462
|
+
<T extends HKTParams<F>[0], U, R1, R2 = void>(
|
|
463
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
464
|
+
onMatch: (
|
|
465
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
466
|
+
) => R1,
|
|
467
|
+
otherwise?: (adt: Exclude<ApplyHKT<F, [T, U]>, Tagged<Tag>>) => R2,
|
|
468
|
+
) => R1 | R2
|
|
469
|
+
: <T extends HKTParams<F>[0], U extends HKTParams<F>[1], R1, R2 = void>(
|
|
470
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
471
|
+
onMatch: (
|
|
472
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
473
|
+
) => R1,
|
|
474
|
+
otherwise?: (adt: Exclude<ApplyHKT<F, [T, U]>, Tagged<Tag>>) => R2,
|
|
475
|
+
) => R1 | R2;
|
|
476
|
+
|
|
477
|
+
// Fallback conditional deconstructor type
|
|
478
|
+
/**
|
|
479
|
+
* A conditional {@link Deconstructor} for an ADT, which is similar to the `if let` syntax in Rust.
|
|
480
|
+
*/
|
|
481
|
+
export type ConditionalDeconstructor<
|
|
482
|
+
Type extends Tagged,
|
|
483
|
+
Tag extends string,
|
|
484
|
+
> = <T extends Type, R1, R2 = void>(
|
|
485
|
+
adt: T,
|
|
486
|
+
onMatch: (...args: ExtractFields<FilterTagged<T, Tag>>) => R1,
|
|
487
|
+
otherwise?: (adt: Exclude<T, Tagged<Tag>>) => R2,
|
|
488
|
+
) => R1 | R2;
|
|
489
|
+
|
|
490
|
+
type MatcherOf<F extends Tagged | TypeLambda<never, Tagged>> =
|
|
491
|
+
[F] extends [Tagged] ?
|
|
492
|
+
{
|
|
493
|
+
<R>(
|
|
494
|
+
adt: F,
|
|
495
|
+
cases: {
|
|
496
|
+
readonly [Tag in F["_tag"]]: (
|
|
497
|
+
...args: ExtractFields<FilterTagged<F, Tag>>
|
|
498
|
+
) => R;
|
|
499
|
+
},
|
|
500
|
+
): R;
|
|
501
|
+
<R>(
|
|
502
|
+
adt: F,
|
|
503
|
+
cases: {
|
|
504
|
+
readonly [Tag in F["_tag"]]?: (
|
|
505
|
+
...args: ExtractFields<FilterTagged<F, Tag>>
|
|
506
|
+
) => R;
|
|
507
|
+
} & { _: (adt: F) => R },
|
|
508
|
+
): R;
|
|
509
|
+
<R>(cases: {
|
|
510
|
+
readonly [Tag in F["_tag"]]: (
|
|
511
|
+
...args: ExtractFields<FilterTagged<F, Tag>>
|
|
512
|
+
) => R;
|
|
513
|
+
}): (adt: F) => R;
|
|
514
|
+
<R>(
|
|
515
|
+
cases: {
|
|
516
|
+
readonly [Tag in F["_tag"]]?: (
|
|
517
|
+
...args: ExtractFields<FilterTagged<F, Tag>>
|
|
518
|
+
) => R;
|
|
519
|
+
} & { _: (adt: F) => R },
|
|
520
|
+
): (adt: F) => R;
|
|
521
|
+
}
|
|
522
|
+
: [F] extends [TypeLambda<[never], Tagged>] ? Matcher1<F>
|
|
523
|
+
: [F] extends [TypeLambda<[never, never], Tagged>] ? Matcher2<F>
|
|
524
|
+
: Matcher<Instantiate<F>>;
|
|
525
|
+
|
|
526
|
+
type Matcher1<F extends TypeLambda<[never], Tagged>> =
|
|
527
|
+
[unknown] extends HKTParams<F> ?
|
|
528
|
+
{
|
|
529
|
+
<T, R>(
|
|
530
|
+
adt: ApplyHKT<F, [T]>,
|
|
531
|
+
cases: {
|
|
532
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
533
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
534
|
+
) => R;
|
|
535
|
+
},
|
|
536
|
+
): R;
|
|
537
|
+
<T, R>(
|
|
538
|
+
adt: ApplyHKT<F, [T]>,
|
|
539
|
+
cases: {
|
|
540
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
541
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
542
|
+
) => R;
|
|
543
|
+
} & { _: (adt: ApplyHKT<F, [T]>) => R },
|
|
544
|
+
): R;
|
|
545
|
+
<T, R>(cases: {
|
|
546
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
547
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
548
|
+
) => R;
|
|
549
|
+
}): (adt: ApplyHKT<F, [T]>) => R;
|
|
550
|
+
<T, R>(
|
|
551
|
+
cases: {
|
|
552
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
553
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
554
|
+
) => R;
|
|
555
|
+
} & { _: (adt: ApplyHKT<F, [T]>) => R },
|
|
556
|
+
): (adt: ApplyHKT<F, [T]>) => R;
|
|
557
|
+
}
|
|
558
|
+
: {
|
|
559
|
+
<T extends HKTParams<F>[0], R>(
|
|
560
|
+
adt: T,
|
|
561
|
+
cases: {
|
|
562
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
563
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
564
|
+
) => R;
|
|
565
|
+
},
|
|
566
|
+
): R;
|
|
567
|
+
<T extends HKTParams<F>[0], R>(
|
|
568
|
+
adt: ApplyHKT<F, [T]>,
|
|
569
|
+
cases: {
|
|
570
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
571
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
572
|
+
) => R;
|
|
573
|
+
} & { _: (adt: ApplyHKT<F, [T]>) => R },
|
|
574
|
+
): R;
|
|
575
|
+
<T extends HKTParams<F>[0], R>(cases: {
|
|
576
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
577
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
578
|
+
) => R;
|
|
579
|
+
}): (adt: ApplyHKT<F, [T]>) => R;
|
|
580
|
+
<T extends HKTParams<F>[0], R>(
|
|
581
|
+
cases: {
|
|
582
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
583
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
584
|
+
) => R;
|
|
585
|
+
} & { _: (adt: ApplyHKT<F, [T]>) => R },
|
|
586
|
+
): (adt: ApplyHKT<F, [T]>) => R;
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
type Matcher2<F extends TypeLambda<[never, never], Tagged>> =
|
|
590
|
+
[unknown, unknown] extends HKTParams<F> ?
|
|
591
|
+
{
|
|
592
|
+
<T, U, R>(
|
|
593
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
594
|
+
cases: {
|
|
595
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
596
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
597
|
+
) => R;
|
|
598
|
+
},
|
|
599
|
+
): R;
|
|
600
|
+
<T, U, R>(
|
|
601
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
602
|
+
cases: {
|
|
603
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
604
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
605
|
+
) => R;
|
|
606
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => R },
|
|
607
|
+
): R;
|
|
608
|
+
<T, U, R>(cases: {
|
|
609
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
610
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
611
|
+
) => R;
|
|
612
|
+
}): (adt: ApplyHKT<F, [T, U]>) => R;
|
|
613
|
+
<T, U, R>(
|
|
614
|
+
cases: {
|
|
615
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
616
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
617
|
+
) => R;
|
|
618
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => R },
|
|
619
|
+
): (adt: ApplyHKT<F, [T, U]>) => R;
|
|
620
|
+
}
|
|
621
|
+
: unknown extends HKTParams<F>[0] ?
|
|
622
|
+
{
|
|
623
|
+
<T, U extends HKTParams<F>[1], R>(
|
|
624
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
625
|
+
cases: {
|
|
626
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
627
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
628
|
+
) => R;
|
|
629
|
+
},
|
|
630
|
+
): R;
|
|
631
|
+
<T, U extends HKTParams<F>[1], R>(
|
|
632
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
633
|
+
cases: {
|
|
634
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
635
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
636
|
+
) => R;
|
|
637
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => R },
|
|
638
|
+
): R;
|
|
639
|
+
<T, U extends HKTParams<F>[1], R>(cases: {
|
|
640
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
641
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
642
|
+
) => R;
|
|
643
|
+
}): (adt: ApplyHKT<F, [T, U]>) => R;
|
|
644
|
+
<T, U extends HKTParams<F>[1], R>(
|
|
645
|
+
cases: {
|
|
646
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
647
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
648
|
+
) => R;
|
|
649
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => R },
|
|
650
|
+
): (adt: ApplyHKT<F, [T, U]>) => R;
|
|
651
|
+
}
|
|
652
|
+
: unknown extends HKTParams<F>[1] ?
|
|
653
|
+
{
|
|
654
|
+
<T extends HKTParams<F>[0], U, R>(
|
|
655
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
656
|
+
cases: {
|
|
657
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
658
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
659
|
+
) => R;
|
|
660
|
+
},
|
|
661
|
+
): R;
|
|
662
|
+
<T extends HKTParams<F>[0], U, R>(
|
|
663
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
664
|
+
cases: {
|
|
665
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
666
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
667
|
+
) => R;
|
|
668
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => R },
|
|
669
|
+
): R;
|
|
670
|
+
<T extends HKTParams<F>[0], U, R>(cases: {
|
|
671
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
672
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
673
|
+
) => R;
|
|
674
|
+
}): (adt: ApplyHKT<F, [T, U]>) => R;
|
|
675
|
+
<T extends HKTParams<F>[0], U, R>(
|
|
676
|
+
cases: {
|
|
677
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
678
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
679
|
+
) => R;
|
|
680
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => R },
|
|
681
|
+
): (adt: ApplyHKT<F, [T, U]>) => R;
|
|
682
|
+
}
|
|
683
|
+
: {
|
|
684
|
+
<T extends HKTParams<F>[0], U extends HKTParams<F>[1], R>(
|
|
685
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
686
|
+
cases: {
|
|
687
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
688
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
689
|
+
) => R;
|
|
690
|
+
},
|
|
691
|
+
): R;
|
|
692
|
+
<T extends HKTParams<F>[0], U extends HKTParams<F>[1], R>(
|
|
693
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
694
|
+
cases: {
|
|
695
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
696
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
697
|
+
) => R;
|
|
698
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => R },
|
|
699
|
+
): R;
|
|
700
|
+
<T extends HKTParams<F>[0], U extends HKTParams<F>[1], R>(cases: {
|
|
701
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
702
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
703
|
+
) => R;
|
|
704
|
+
}): (adt: ApplyHKT<F, [T, U]>) => R;
|
|
705
|
+
<T extends HKTParams<F>[0], U extends HKTParams<F>[1], R>(
|
|
706
|
+
cases: {
|
|
707
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
708
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
709
|
+
) => R;
|
|
710
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => R },
|
|
711
|
+
): (adt: ApplyHKT<F, [T, U]>) => R;
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
// Fallback matcher type
|
|
715
|
+
/**
|
|
716
|
+
* A {@linkcode match} function for a specific ADT.
|
|
717
|
+
*/
|
|
718
|
+
export interface Matcher<Type extends Tagged> {
|
|
719
|
+
<T extends Type, R>(
|
|
720
|
+
adt: T,
|
|
721
|
+
cases: {
|
|
722
|
+
readonly [Tag in Type["_tag"]]: (
|
|
723
|
+
...args: ExtractFields<FilterTagged<T, Tag>>
|
|
724
|
+
) => R;
|
|
725
|
+
},
|
|
726
|
+
): R;
|
|
727
|
+
<T extends Type, R>(
|
|
728
|
+
adt: T,
|
|
729
|
+
cases: {
|
|
730
|
+
readonly [Tag in Type["_tag"]]?: (
|
|
731
|
+
...args: ExtractFields<FilterTagged<T, Tag>>
|
|
732
|
+
) => R;
|
|
733
|
+
} & { _: (adt: T) => R },
|
|
734
|
+
): R;
|
|
735
|
+
<T extends Type, R>(cases: {
|
|
736
|
+
readonly [Tag in Type["_tag"]]: (
|
|
737
|
+
...args: ExtractFields<FilterTagged<T, Tag>>
|
|
738
|
+
) => R;
|
|
739
|
+
}): (adt: T) => R;
|
|
740
|
+
<T extends Type, R>(
|
|
741
|
+
cases: {
|
|
742
|
+
readonly [Tag in Type["_tag"]]?: (
|
|
743
|
+
...args: ExtractFields<FilterTagged<T, Tag>>
|
|
744
|
+
) => R;
|
|
745
|
+
} & { _: (adt: T) => R },
|
|
746
|
+
): (adt: T) => R;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
type MatcherOfW<F extends Tagged | TypeLambda<never, Tagged>> =
|
|
750
|
+
[F] extends [Tagged] ?
|
|
751
|
+
{
|
|
752
|
+
<
|
|
753
|
+
Cases extends {
|
|
754
|
+
readonly [Tag in F["_tag"]]: (
|
|
755
|
+
...args: ExtractFields<FilterTagged<F, Tag>>
|
|
756
|
+
) => unknown;
|
|
757
|
+
},
|
|
758
|
+
>(
|
|
759
|
+
adt: F,
|
|
760
|
+
cases: Cases,
|
|
761
|
+
): ReturnType<ValueOf<Cases>>;
|
|
762
|
+
<
|
|
763
|
+
Cases extends {
|
|
764
|
+
readonly [Tag in F["_tag"]]?: (
|
|
765
|
+
...args: ExtractFields<FilterTagged<F, Tag>>
|
|
766
|
+
) => unknown;
|
|
767
|
+
} & { _: (adt: F) => unknown },
|
|
768
|
+
>(
|
|
769
|
+
adt: F,
|
|
770
|
+
cases: Cases,
|
|
771
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
772
|
+
<
|
|
773
|
+
Cases extends {
|
|
774
|
+
readonly [Tag in F["_tag"]]: (
|
|
775
|
+
...args: ExtractFields<FilterTagged<F, Tag>>
|
|
776
|
+
) => unknown;
|
|
777
|
+
},
|
|
778
|
+
>(
|
|
779
|
+
cases: Cases,
|
|
780
|
+
): (adt: F) => ReturnType<ValueOf<Cases>>;
|
|
781
|
+
<
|
|
782
|
+
Cases extends {
|
|
783
|
+
readonly [Tag in F["_tag"]]?: (
|
|
784
|
+
...args: ExtractFields<FilterTagged<F, Tag>>
|
|
785
|
+
) => unknown;
|
|
786
|
+
} & { _: (adt: F) => unknown },
|
|
787
|
+
>(
|
|
788
|
+
cases: Cases,
|
|
789
|
+
): (
|
|
790
|
+
adt: F,
|
|
791
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
792
|
+
}
|
|
793
|
+
: [F] extends [TypeLambda<[never], Tagged>] ? Matcher1W<F>
|
|
794
|
+
: [F] extends [TypeLambda<[never, never], Tagged>] ? Matcher2W<F>
|
|
795
|
+
: MatcherW<Instantiate<F>>;
|
|
796
|
+
|
|
797
|
+
type Matcher1W<F extends TypeLambda<[never], Tagged>> =
|
|
798
|
+
[unknown] extends HKTParams<F> ?
|
|
799
|
+
{
|
|
800
|
+
<
|
|
801
|
+
T,
|
|
802
|
+
R,
|
|
803
|
+
Cases extends {
|
|
804
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
805
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
806
|
+
) => unknown;
|
|
807
|
+
},
|
|
808
|
+
>(
|
|
809
|
+
adt: ApplyHKT<F, [T]>,
|
|
810
|
+
cases: Cases,
|
|
811
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
812
|
+
<
|
|
813
|
+
T,
|
|
814
|
+
R,
|
|
815
|
+
Cases extends {
|
|
816
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
817
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
818
|
+
) => R;
|
|
819
|
+
} & { _: (adt: ApplyHKT<F, [T]>) => R },
|
|
820
|
+
>(
|
|
821
|
+
adt: ApplyHKT<F, [T]>,
|
|
822
|
+
cases: Cases,
|
|
823
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
824
|
+
<
|
|
825
|
+
T,
|
|
826
|
+
R,
|
|
827
|
+
Cases extends {
|
|
828
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
829
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
830
|
+
) => unknown;
|
|
831
|
+
},
|
|
832
|
+
>(
|
|
833
|
+
cases: Cases,
|
|
834
|
+
): (
|
|
835
|
+
adt: ApplyHKT<F, [T]>,
|
|
836
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
837
|
+
<
|
|
838
|
+
T,
|
|
839
|
+
R,
|
|
840
|
+
Cases extends {
|
|
841
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
842
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
843
|
+
) => R;
|
|
844
|
+
} & { _: (adt: ApplyHKT<F, [T]>) => R },
|
|
845
|
+
>(
|
|
846
|
+
cases: Cases,
|
|
847
|
+
): (
|
|
848
|
+
adt: ApplyHKT<F, [T]>,
|
|
849
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
850
|
+
}
|
|
851
|
+
: {
|
|
852
|
+
<
|
|
853
|
+
T extends HKTParams<F>[0],
|
|
854
|
+
Cases extends {
|
|
855
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
856
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
857
|
+
) => unknown;
|
|
858
|
+
},
|
|
859
|
+
>(
|
|
860
|
+
adt: T,
|
|
861
|
+
cases: Cases,
|
|
862
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
863
|
+
<
|
|
864
|
+
T extends HKTParams<F>[0],
|
|
865
|
+
Cases extends {
|
|
866
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
867
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
868
|
+
) => unknown;
|
|
869
|
+
} & { _: (adt: ApplyHKT<F, [T]>) => unknown },
|
|
870
|
+
>(
|
|
871
|
+
adt: ApplyHKT<F, [T]>,
|
|
872
|
+
cases: Cases,
|
|
873
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
874
|
+
<
|
|
875
|
+
T extends HKTParams<F>[0],
|
|
876
|
+
Cases extends {
|
|
877
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
878
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
879
|
+
) => unknown;
|
|
880
|
+
},
|
|
881
|
+
>(
|
|
882
|
+
cases: Cases,
|
|
883
|
+
): (
|
|
884
|
+
adt: ApplyHKT<F, [T]>,
|
|
885
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
886
|
+
<
|
|
887
|
+
T extends HKTParams<F>[0],
|
|
888
|
+
Cases extends {
|
|
889
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
890
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T]>, Tag>>
|
|
891
|
+
) => unknown;
|
|
892
|
+
} & { _: (adt: ApplyHKT<F, [T]>) => unknown },
|
|
893
|
+
>(
|
|
894
|
+
cases: Cases,
|
|
895
|
+
): (
|
|
896
|
+
adt: ApplyHKT<F, [T]>,
|
|
897
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
898
|
+
};
|
|
899
|
+
|
|
900
|
+
type Matcher2W<F extends TypeLambda<[never, never], Tagged>> =
|
|
901
|
+
[unknown, unknown] extends HKTParams<F> ?
|
|
902
|
+
{
|
|
903
|
+
<
|
|
904
|
+
T,
|
|
905
|
+
U,
|
|
906
|
+
Cases extends {
|
|
907
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
908
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
909
|
+
) => unknown;
|
|
910
|
+
},
|
|
911
|
+
>(
|
|
912
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
913
|
+
cases: Cases,
|
|
914
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
915
|
+
<
|
|
916
|
+
T,
|
|
917
|
+
U,
|
|
918
|
+
Cases extends {
|
|
919
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
920
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
921
|
+
) => unknown;
|
|
922
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => unknown },
|
|
923
|
+
>(
|
|
924
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
925
|
+
cases: Cases,
|
|
926
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
927
|
+
<
|
|
928
|
+
T,
|
|
929
|
+
U,
|
|
930
|
+
Cases extends {
|
|
931
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
932
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
933
|
+
) => unknown;
|
|
934
|
+
},
|
|
935
|
+
>(
|
|
936
|
+
cases: Cases,
|
|
937
|
+
): (
|
|
938
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
939
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
940
|
+
<
|
|
941
|
+
T,
|
|
942
|
+
U,
|
|
943
|
+
Cases extends {
|
|
944
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
945
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
946
|
+
) => unknown;
|
|
947
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => unknown },
|
|
948
|
+
>(
|
|
949
|
+
cases: Cases,
|
|
950
|
+
): (
|
|
951
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
952
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
953
|
+
}
|
|
954
|
+
: unknown extends HKTParams<F>[0] ?
|
|
955
|
+
{
|
|
956
|
+
<
|
|
957
|
+
T,
|
|
958
|
+
U extends HKTParams<F>[1],
|
|
959
|
+
Cases extends {
|
|
960
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
961
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
962
|
+
) => unknown;
|
|
963
|
+
},
|
|
964
|
+
>(
|
|
965
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
966
|
+
cases: Cases,
|
|
967
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
968
|
+
<
|
|
969
|
+
T,
|
|
970
|
+
U extends HKTParams<F>[1],
|
|
971
|
+
Cases extends {
|
|
972
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
973
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
974
|
+
) => unknown;
|
|
975
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => unknown },
|
|
976
|
+
>(
|
|
977
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
978
|
+
cases: Cases,
|
|
979
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
980
|
+
<
|
|
981
|
+
T,
|
|
982
|
+
U extends HKTParams<F>[1],
|
|
983
|
+
Cases extends {
|
|
984
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
985
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
986
|
+
) => unknown;
|
|
987
|
+
},
|
|
988
|
+
>(
|
|
989
|
+
cases: Cases,
|
|
990
|
+
): (
|
|
991
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
992
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
993
|
+
<
|
|
994
|
+
T,
|
|
995
|
+
U extends HKTParams<F>[1],
|
|
996
|
+
Cases extends {
|
|
997
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
998
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
999
|
+
) => unknown;
|
|
1000
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => unknown },
|
|
1001
|
+
>(
|
|
1002
|
+
cases: Cases,
|
|
1003
|
+
): (
|
|
1004
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
1005
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1006
|
+
}
|
|
1007
|
+
: unknown extends HKTParams<F>[1] ?
|
|
1008
|
+
{
|
|
1009
|
+
<
|
|
1010
|
+
T extends HKTParams<F>[0],
|
|
1011
|
+
U,
|
|
1012
|
+
Cases extends {
|
|
1013
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
1014
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
1015
|
+
) => unknown;
|
|
1016
|
+
},
|
|
1017
|
+
>(
|
|
1018
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
1019
|
+
cases: Cases,
|
|
1020
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1021
|
+
<
|
|
1022
|
+
T extends HKTParams<F>[0],
|
|
1023
|
+
U,
|
|
1024
|
+
Cases extends {
|
|
1025
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
1026
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
1027
|
+
) => unknown;
|
|
1028
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => unknown },
|
|
1029
|
+
>(
|
|
1030
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
1031
|
+
cases: Cases,
|
|
1032
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1033
|
+
<
|
|
1034
|
+
T extends HKTParams<F>[0],
|
|
1035
|
+
U,
|
|
1036
|
+
Cases extends {
|
|
1037
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
1038
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
1039
|
+
) => unknown;
|
|
1040
|
+
},
|
|
1041
|
+
>(
|
|
1042
|
+
cases: Cases,
|
|
1043
|
+
): (
|
|
1044
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
1045
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1046
|
+
<
|
|
1047
|
+
T extends HKTParams<F>[0],
|
|
1048
|
+
U,
|
|
1049
|
+
Cases extends {
|
|
1050
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
1051
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
1052
|
+
) => unknown;
|
|
1053
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => unknown },
|
|
1054
|
+
>(
|
|
1055
|
+
cases: Cases,
|
|
1056
|
+
): (
|
|
1057
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
1058
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1059
|
+
}
|
|
1060
|
+
: {
|
|
1061
|
+
<
|
|
1062
|
+
T extends HKTParams<F>[0],
|
|
1063
|
+
U extends HKTParams<F>[1],
|
|
1064
|
+
Cases extends {
|
|
1065
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
1066
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
1067
|
+
) => unknown;
|
|
1068
|
+
},
|
|
1069
|
+
>(
|
|
1070
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
1071
|
+
cases: Cases,
|
|
1072
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1073
|
+
<
|
|
1074
|
+
T extends HKTParams<F>[0],
|
|
1075
|
+
U extends HKTParams<F>[1],
|
|
1076
|
+
Cases extends {
|
|
1077
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
1078
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
1079
|
+
) => unknown;
|
|
1080
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => unknown },
|
|
1081
|
+
>(
|
|
1082
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
1083
|
+
cases: Cases,
|
|
1084
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1085
|
+
<
|
|
1086
|
+
T extends HKTParams<F>[0],
|
|
1087
|
+
U extends HKTParams<F>[1],
|
|
1088
|
+
Cases extends {
|
|
1089
|
+
readonly [Tag in Instantiate<F>["_tag"]]: (
|
|
1090
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
1091
|
+
) => unknown;
|
|
1092
|
+
},
|
|
1093
|
+
>(
|
|
1094
|
+
cases: Cases,
|
|
1095
|
+
): (
|
|
1096
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
1097
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1098
|
+
<
|
|
1099
|
+
T extends HKTParams<F>[0],
|
|
1100
|
+
U extends HKTParams<F>[1],
|
|
1101
|
+
Cases extends {
|
|
1102
|
+
readonly [Tag in Instantiate<F>["_tag"]]?: (
|
|
1103
|
+
...args: ExtractFields<FilterTagged<ApplyHKT<F, [T, U]>, Tag>>
|
|
1104
|
+
) => unknown;
|
|
1105
|
+
} & { _: (adt: ApplyHKT<F, [T, U]>) => unknown },
|
|
1106
|
+
>(
|
|
1107
|
+
cases: Cases,
|
|
1108
|
+
): (
|
|
1109
|
+
adt: ApplyHKT<F, [T, U]>,
|
|
1110
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1111
|
+
};
|
|
1112
|
+
|
|
1113
|
+
// Fallback matcher type
|
|
1114
|
+
/**
|
|
1115
|
+
* A {@linkcode matchW} function for a specific ADT.
|
|
1116
|
+
*/
|
|
1117
|
+
export interface MatcherW<Type extends Tagged> {
|
|
1118
|
+
<
|
|
1119
|
+
T extends Type,
|
|
1120
|
+
Cases extends {
|
|
1121
|
+
readonly [Tag in Type["_tag"]]: (
|
|
1122
|
+
...args: ExtractFields<FilterTagged<T, Tag>>
|
|
1123
|
+
) => unknown;
|
|
1124
|
+
},
|
|
1125
|
+
>(
|
|
1126
|
+
adt: T,
|
|
1127
|
+
cases: Cases,
|
|
1128
|
+
): ReturnType<ValueOf<Cases>>;
|
|
1129
|
+
<
|
|
1130
|
+
T extends Type,
|
|
1131
|
+
Cases extends {
|
|
1132
|
+
readonly [Tag in Type["_tag"]]?: (
|
|
1133
|
+
...args: ExtractFields<FilterTagged<T, Tag>>
|
|
1134
|
+
) => unknown;
|
|
1135
|
+
} & { _: (adt: T) => unknown },
|
|
1136
|
+
>(
|
|
1137
|
+
adt: T,
|
|
1138
|
+
cases: Cases,
|
|
1139
|
+
): ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1140
|
+
<
|
|
1141
|
+
T extends Type,
|
|
1142
|
+
Cases extends {
|
|
1143
|
+
readonly [Tag in Type["_tag"]]: (
|
|
1144
|
+
...args: ExtractFields<FilterTagged<T, Tag>>
|
|
1145
|
+
) => unknown;
|
|
1146
|
+
},
|
|
1147
|
+
>(
|
|
1148
|
+
cases: Cases,
|
|
1149
|
+
): (adt: T) => ReturnType<ValueOf<Cases>>;
|
|
1150
|
+
<
|
|
1151
|
+
T extends Type,
|
|
1152
|
+
Cases extends {
|
|
1153
|
+
readonly [Tag in Type["_tag"]]?: (
|
|
1154
|
+
...args: ExtractFields<FilterTagged<T, Tag>>
|
|
1155
|
+
) => unknown;
|
|
1156
|
+
} & { _: (adt: T) => unknown },
|
|
1157
|
+
>(
|
|
1158
|
+
cases: Cases,
|
|
1159
|
+
): (
|
|
1160
|
+
adt: T,
|
|
1161
|
+
) => ReturnType<Extract<ValueOf<Cases>, (...args: never) => unknown>>;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
/*****************
|
|
1165
|
+
* Utility types *
|
|
1166
|
+
*****************/
|
|
1167
|
+
/**
|
|
1168
|
+
* Instantiate a possibly higher-kinded {@linkcode Tagged}.
|
|
1169
|
+
* @private
|
|
1170
|
+
*/
|
|
1171
|
+
type Instantiate<F extends Tagged | TypeLambda<never, Tagged>> =
|
|
1172
|
+
(F extends TypeLambda ? TolerantResult<F> : F) extends (
|
|
1173
|
+
infer R extends Tagged
|
|
1174
|
+
) ?
|
|
1175
|
+
R
|
|
1176
|
+
: never;
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* {@link Extract} a {@linkcode Tagged} from a union of {@linkcode Tagged}s.
|
|
1180
|
+
*/
|
|
1181
|
+
type FilterTagged<T, Tag extends string> = Extract<T, { readonly _tag: Tag }>;
|
|
1182
|
+
|
|
1183
|
+
/**
|
|
1184
|
+
* Extract the fields of a {@linkcode Tagged} as a (possibly) labeled tuple.
|
|
1185
|
+
*/
|
|
1186
|
+
type ExtractFields<F> = AddLabels<
|
|
1187
|
+
_ExtractFields<F>,
|
|
1188
|
+
F extends (
|
|
1189
|
+
Tagged<
|
|
1190
|
+
string,
|
|
1191
|
+
| (infer Labels extends readonly unknown[])
|
|
1192
|
+
| { readonly __labels: infer Labels extends readonly unknown[] }
|
|
1193
|
+
>
|
|
1194
|
+
) ?
|
|
1195
|
+
Labels
|
|
1196
|
+
: []
|
|
1197
|
+
>;
|
|
1198
|
+
type _ExtractFields<
|
|
1199
|
+
F,
|
|
1200
|
+
Counter extends void[] = [],
|
|
1201
|
+
Acc extends unknown[] = [],
|
|
1202
|
+
> =
|
|
1203
|
+
F extends { readonly [K in `_${Counter["length"]}`]: infer T } ?
|
|
1204
|
+
_ExtractFields<F, [...Counter, void], [...Acc, T]>
|
|
1205
|
+
: Acc;
|
|
1206
|
+
|
|
1207
|
+
/************************
|
|
1208
|
+
* Common utility types *
|
|
1209
|
+
************************/
|
|
1210
|
+
/**
|
|
1211
|
+
* Get the value type of an object type.
|
|
1212
|
+
* @private
|
|
1213
|
+
*/
|
|
1214
|
+
type ValueOf<T> = T[keyof T];
|
|
1215
|
+
|
|
1216
|
+
/**
|
|
1217
|
+
* Check if a type is `never`.
|
|
1218
|
+
* @private
|
|
1219
|
+
*/
|
|
1220
|
+
type IsNever<T> = [T] extends [never] ? true : false;
|
|
1221
|
+
|
|
1222
|
+
/**
|
|
1223
|
+
* Check if a type is `any`.
|
|
1224
|
+
*
|
|
1225
|
+
* Copied from [type-fest](https://github.com/sindresorhus/type-fest/blob/475a737e3223d7bd8e950f36998a17d520a93e4b/source/is-any.d.ts#L33).
|
|
1226
|
+
* @private
|
|
1227
|
+
*/
|
|
1228
|
+
type IsAny<T> = 0 extends 1 & NoInfer<T> ? true : false;
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* Convert a `string` type to a `number` type.
|
|
1232
|
+
* @private
|
|
1233
|
+
*/
|
|
1234
|
+
type StringToNumber<S> = S extends `${infer N extends number}` ? N : never;
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* Get numeric index of an object or a tuple type.
|
|
1238
|
+
* @private
|
|
1239
|
+
*/
|
|
1240
|
+
type IndexOf<T, Counter extends void[] = [], Acc extends number = never> =
|
|
1241
|
+
T extends readonly unknown[] ?
|
|
1242
|
+
Counter["length"] extends T["length"] ?
|
|
1243
|
+
Acc & keyof T
|
|
1244
|
+
: IndexOf<T, [...Counter, void], Acc | Counter["length"]>
|
|
1245
|
+
: keyof T & number;
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
* Simply merge two object types and t. Optional keys are not considered.
|
|
1249
|
+
* @private
|
|
1250
|
+
*/
|
|
1251
|
+
// NOTE: DO NOT add `extends infer R ? { [K in keyof R]: R[K] } : never` after the type definition
|
|
1252
|
+
// (which is a common hacking to make type information more readable), since it will cause
|
|
1253
|
+
// TypeScript to deeply evaluate the type, which we’ll lose tuple labels in the process.
|
|
1254
|
+
type Merge<L, R> = {
|
|
1255
|
+
// This `readonly` modifier amazingly makes TS to infer a more readable type in some cases,
|
|
1256
|
+
// e.g., `function safeDiv(n: number, d: number) { return d === 0 ? none : some(n / d); }`
|
|
1257
|
+
// will infer `Option<number>` instead of `Constructor<OptionHKT, "None"> | Option<number>`.
|
|
1258
|
+
// I don’t understand why it works, but it works.
|
|
1259
|
+
readonly [K in keyof L | keyof R]: K extends keyof L ? L[K]
|
|
1260
|
+
: K extends keyof R ? R[K]
|
|
1261
|
+
: never;
|
|
1262
|
+
};
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* {@link Merge} multiple object types. Optional keys are not considered.
|
|
1266
|
+
* @private
|
|
1267
|
+
*/
|
|
1268
|
+
type Spread<A, B, C = {}, D = {}, E = {}, F = {}, G = {}, H = {}> =
|
|
1269
|
+
Merge<
|
|
1270
|
+
A,
|
|
1271
|
+
Merge<B, Merge<C, Merge<D, Merge<E, Merge<F, Merge<G, H>>>>>>
|
|
1272
|
+
> extends infer R ?
|
|
1273
|
+
{ [K in keyof R]: R[K] }
|
|
1274
|
+
: never;
|
|
1275
|
+
|
|
1276
|
+
/**
|
|
1277
|
+
* Add labels to a tuple type.
|
|
1278
|
+
* @private
|
|
1279
|
+
*
|
|
1280
|
+
* @example
|
|
1281
|
+
* ```typescript
|
|
1282
|
+
* type _1 = AddLabels<[1, 2, 3], [a: void, b: void, c: void]>; // => [a: 1, b: 2, c: 3]
|
|
1283
|
+
* type _2 = AddLabels<[1, 2, 3], [a: void, b: void]>; // => [a: 1, b: 2, 3]
|
|
1284
|
+
* type _3 = AddLabels<[1, 2], [a: void, b: void, c: void]>; // => [a: 1, b: 2]
|
|
1285
|
+
* ```
|
|
1286
|
+
*/
|
|
1287
|
+
type AddLabels<
|
|
1288
|
+
TS extends unknown[],
|
|
1289
|
+
Labels extends readonly unknown[],
|
|
1290
|
+
Acc extends unknown[] = [],
|
|
1291
|
+
> =
|
|
1292
|
+
Labels extends [unknown, ...infer RestLabels] ?
|
|
1293
|
+
TS extends [infer Head, ...infer Tail] ?
|
|
1294
|
+
AddLabels<
|
|
1295
|
+
Tail,
|
|
1296
|
+
RestLabels,
|
|
1297
|
+
[...Acc, ...WrapLabel<Head, HeadPart<Labels>>]
|
|
1298
|
+
>
|
|
1299
|
+
: Acc
|
|
1300
|
+
: [...Acc, ...TS];
|
|
1301
|
+
type WrapLabel<T, Label> =
|
|
1302
|
+
{ [K in keyof Label]: T } extends infer Part extends readonly [unknown] ? Part
|
|
1303
|
+
: never;
|
|
1304
|
+
|
|
1305
|
+
/**
|
|
1306
|
+
* Remove the first element from a tuple type (label is preserved).
|
|
1307
|
+
* @private
|
|
1308
|
+
*
|
|
1309
|
+
* @example
|
|
1310
|
+
* ```typescript
|
|
1311
|
+
* type _1 = Tail<[1, 2, 3]>; // => [2, 3]
|
|
1312
|
+
* type _2 = Tail<[1]>; // => []
|
|
1313
|
+
* type _3 = Tail<[]>; // => []
|
|
1314
|
+
* type _4 = Tail<[a: 1, b: 2, c: 3]>; // => [b: 2, c: 3]
|
|
1315
|
+
* ```
|
|
1316
|
+
*/
|
|
1317
|
+
type Tail<TS> =
|
|
1318
|
+
TS extends [unknown, ...infer Tail] ? Tail
|
|
1319
|
+
: TS extends readonly [unknown, ...infer Tail] ? readonly [...Tail]
|
|
1320
|
+
: TS extends [] ? []
|
|
1321
|
+
: TS extends readonly [] ? readonly []
|
|
1322
|
+
: never;
|
|
1323
|
+
/**
|
|
1324
|
+
* Get the initial elements of a tuple type (label is preserved).
|
|
1325
|
+
* @private
|
|
1326
|
+
*
|
|
1327
|
+
* @example
|
|
1328
|
+
* ```typescript
|
|
1329
|
+
* type _1 = Init<[1, 2, 3]>; // => [1, 2]
|
|
1330
|
+
* type _2 = Init<[1]>; // => []
|
|
1331
|
+
* type _3 = Init<[]>; // => []
|
|
1332
|
+
* type _4 = Init<[a: 1, b: 2, c: 3]>; // => [a: 1, b: 2]
|
|
1333
|
+
* ```
|
|
1334
|
+
*/
|
|
1335
|
+
type Init<TS> =
|
|
1336
|
+
TS extends [...infer Init, unknown] ? Init
|
|
1337
|
+
: TS extends readonly [...infer Init, unknown] ? readonly [...Init]
|
|
1338
|
+
: TS extends [] ? []
|
|
1339
|
+
: TS extends readonly [] ? readonly []
|
|
1340
|
+
: never;
|
|
1341
|
+
/**
|
|
1342
|
+
* Get the head part of a tuple type (label is preserved).
|
|
1343
|
+
* @private
|
|
1344
|
+
*
|
|
1345
|
+
* @example
|
|
1346
|
+
* ```typescript
|
|
1347
|
+
* type _1 = HeadPart<[1, 2, 3]>; // => [1]
|
|
1348
|
+
* type _2 = HeadPart<[1]>; // => [1]
|
|
1349
|
+
* type _3 = HeadPart<[]>; // => []
|
|
1350
|
+
* type _4 = HeadPart<[a: 1, b: 2, c: 3]>; // => [a: 1]
|
|
1351
|
+
* ```
|
|
1352
|
+
*/
|
|
1353
|
+
type HeadPart<TS, Result = TS> =
|
|
1354
|
+
Result extends readonly [] | readonly [unknown] ? Result
|
|
1355
|
+
: HeadPart<Tail<TS>, Init<Result>>;
|
|
1356
|
+
|
|
1357
|
+
/***************
|
|
1358
|
+
* HKT related *
|
|
1359
|
+
***************/
|
|
1360
|
+
/**
|
|
1361
|
+
* An **HKT** (**H**igher-**K**inded **T**ype) compatible with the
|
|
1362
|
+
* [hkt-core](https://github.com/Snowflyt/hkt-core) V1 standard.
|
|
1363
|
+
*/
|
|
1364
|
+
interface TypeLambda<in Params extends unknown[] = any, out RetType = any> {
|
|
1365
|
+
/**
|
|
1366
|
+
* Metadata of the {@linkcode TypeLambda}.
|
|
1367
|
+
*/
|
|
1368
|
+
readonly "~hkt": TypeLambdaMeta;
|
|
1369
|
+
|
|
1370
|
+
/**
|
|
1371
|
+
* type-level signature of the {@linkcode TypeLambda}.
|
|
1372
|
+
*/
|
|
1373
|
+
readonly signature: (...args: Params) => RetType;
|
|
1374
|
+
}
|
|
1375
|
+
/**
|
|
1376
|
+
* Metadata of a {@linkcode TypeLambda}.
|
|
1377
|
+
*/
|
|
1378
|
+
interface TypeLambdaMeta {
|
|
1379
|
+
/**
|
|
1380
|
+
* The version number of the {@linkcode TypeLambda} specification.
|
|
1381
|
+
*/
|
|
1382
|
+
readonly version: 1;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
/**
|
|
1386
|
+
* Apply an HKT with arguments.
|
|
1387
|
+
*/
|
|
1388
|
+
type ApplyHKT<F, Args> =
|
|
1389
|
+
F & { readonly Args: (_: Args) => void } extends (
|
|
1390
|
+
infer F extends { readonly return: unknown }
|
|
1391
|
+
) ?
|
|
1392
|
+
F["return"]
|
|
1393
|
+
: never;
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* Get the declared parameter types of an HKT.
|
|
1397
|
+
*/
|
|
1398
|
+
type HKTParams<F> =
|
|
1399
|
+
F extends { readonly signature: (...args: infer Params) => unknown } ? Params
|
|
1400
|
+
: never;
|
|
1401
|
+
|
|
1402
|
+
/**
|
|
1403
|
+
* Get a _tolerant_ result of an HKT.
|
|
1404
|
+
* @private
|
|
1405
|
+
*
|
|
1406
|
+
* @example
|
|
1407
|
+
* ```typescript
|
|
1408
|
+
* interface OptionHKT extends HKT {
|
|
1409
|
+
* return: Option<Arg0<this>>;
|
|
1410
|
+
* }
|
|
1411
|
+
*
|
|
1412
|
+
* type _1 = TolerantResult<OptionHKT>; // => Option<unknown>
|
|
1413
|
+
* ```
|
|
1414
|
+
*/
|
|
1415
|
+
export type TolerantResult<F extends TypeLambda> =
|
|
1416
|
+
HKTParams<F> extends infer Params extends unknown[] ?
|
|
1417
|
+
ApplyHKT<
|
|
1418
|
+
F,
|
|
1419
|
+
{
|
|
1420
|
+
[K in keyof Params]: _TestParameterVarianceAtIndex<
|
|
1421
|
+
F,
|
|
1422
|
+
StringToNumber<K>
|
|
1423
|
+
> extends infer Variance ?
|
|
1424
|
+
Variance extends "invariant" ? any
|
|
1425
|
+
: Variance extends "contravariant" ? never
|
|
1426
|
+
: _UpperBound<Params[K]>
|
|
1427
|
+
: never;
|
|
1428
|
+
}
|
|
1429
|
+
>
|
|
1430
|
+
: never;
|
|
1431
|
+
// Infer the variance of each type parameter for a specific parameter or return type
|
|
1432
|
+
// The implementation refers to the description of variance inference in the Python typing
|
|
1433
|
+
// documentation: https://typing.readthedocs.io/en/latest/spec/generics.html#variance-inference
|
|
1434
|
+
type _TestParameterVarianceAtIndex<F extends TypeLambda, Index extends number> =
|
|
1435
|
+
HKTParams<F> extends infer Params extends unknown[] ?
|
|
1436
|
+
_CheckVariance<
|
|
1437
|
+
ApplyHKT<F, { [K in keyof Params]: never }>,
|
|
1438
|
+
ApplyHKT<
|
|
1439
|
+
F,
|
|
1440
|
+
{
|
|
1441
|
+
[K in keyof Params]: StringToNumber<K> extends Index ?
|
|
1442
|
+
_UpperBound<Params[K]>
|
|
1443
|
+
: never;
|
|
1444
|
+
}
|
|
1445
|
+
>
|
|
1446
|
+
>
|
|
1447
|
+
: never;
|
|
1448
|
+
type _UpperBound<T> = IsAny<T> extends true ? unknown : T;
|
|
1449
|
+
type _CheckVariance<Lower, Upper> =
|
|
1450
|
+
[Lower] extends [Upper] ?
|
|
1451
|
+
[Upper] extends [Lower] ?
|
|
1452
|
+
"irrelevant"
|
|
1453
|
+
: "covariant"
|
|
1454
|
+
: [Upper] extends [Lower] ? "contravariant"
|
|
1455
|
+
: "invariant";
|