1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
type TagValue<T, N> = T extends Tag<N, infer V> ? V : never
export const match = <R, T extends Tag<string, any>>(
tag: T,
pattern: {
[key in T['tag'] | '_']?: (v: TagValue<T, key>) => R
},
): R => ((pattern as any)[tag.tag] || (pattern._ as any))(tag.value)
// type TagValues<
// T extends Tag<any, string>,
// Keys extends Array<string>,
// Values extends Array<any> = [],
// > = Keys extends []
// ? Values
// : Keys extends [
// infer key extends string,
// ...infer restOfKeys extends string[],
// ]
// ? TagValues<T, restOfKeys, [...Values, TagValue<T, key>]>
// : never
//
// export const ifLet = <T extends Tag<string, any>, Keys extends Array<T['tag']>>(
// tag: T,
// kinds: Keys,
// cb: (...values: TagValues<T, Keys>) => void,
// ): void => {
// const values = kinds.map(k => (tag.tag === k ? tag.value : undefined))
// ;(cb as any)(...values)
// }
export const matchString = <R, T extends string = string>(
key: T,
pattern: {
[key in T | '_']?: (key: key) => R
},
): R => ((pattern as any)[key] || (pattern._ as any))(key)
type Tag<N, V> = { tag: N; value: V }
export type Enum<T> = { [N in keyof T]: Tag<N, T[N]> }[keyof T]
export const constructors = <T extends Tag<string, any>>(): {
[N in T['tag']]: TagValue<T, N> extends null | never
? (value?: null | never) => T
: (value: TagValue<T, N>) => T
} =>
new Proxy(
{},
{
get(_, k) {
return (value: any) => ({ tag: k, value })
},
},
) as any
|