summaryrefslogtreecommitdiff
path: root/src/utils/adt.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/adt.ts')
-rw-r--r--src/utils/adt.ts32
1 files changed, 32 insertions, 0 deletions
diff --git a/src/utils/adt.ts b/src/utils/adt.ts
new file mode 100644
index 0000000..45d9e50
--- /dev/null
+++ b/src/utils/adt.ts
@@ -0,0 +1,32 @@
+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