aboutsummaryrefslogtreecommitdiff
path: root/src/utils/adt.ts
blob: 78ab66731cade23eb180e5edab54e9e9423b57d1 (plain) (blame)
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
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)

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