Skip to content

Instantly share code, notes, and snippets.

@tongyul
Last active July 30, 2023 10:08
Show Gist options
  • Save tongyul/4d6515e024b10e5f0763b354d7439bff to your computer and use it in GitHub Desktop.
Save tongyul/4d6515e024b10e5f0763b354d7439bff to your computer and use it in GitHub Desktop.
TypeScript discriminated union & a poor man's match statement | Rust-like enum | Haskell data | SML datatype
type EnumLike<K extends string> = { kind: K, value: any };
type EnumMatchTable<E extends EnumLike<string>, T> = {
[Variant in E as Variant["kind"]]: (_: Variant["value"]) => T;
}
export type Case<K extends string, T> = { kind: K, value: T };
export const caseConstructor =
<K extends string>(kind: K) =>
<T,>(value: T) : Case<K, T> => ({ kind, value });
export const match =
<K extends string, E extends EnumLike<K>, T>
(e: E, fs: EnumMatchTable<E, T>): T => fs[e.kind](e.value);
import { Case, match } from 'enum.ts';
// inspired by CMU's 15-150 course
export type Tree<T> =
Case<"Empty", undefined> | Case<"Node", [Tree<T>, T, Tree<T>]>;
export const inOrder = <T,>(t: Tree<T>): T[] =>
match(t, {
Empty: (_: undefined) => [],
Node: ([l, x, r]: [Tree<T>, T, Tree<T>]) =>
[...inOrder(l), x, ...inOrder(r)],
});
import { Case, caseConstructor, match } from 'enum.ts';
type Result<T, E> = Case<"Ok", T> | Case<"Err", E>;
// ...
declare const someResult:
Result<{ url: string }, { code: number, msg: string }>;
const _: void = await match(someResult, {
Ok: async ({ url }: { url: string }) => {
console.log(`The resource URL is ${url}`);
},
Err: async ({ code, msg }: { code: number, msg: string }) => {
console.log(`The request returned with code ${code} and message ${msg}`);
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment