Skip to content

Instantly share code, notes, and snippets.

@tokland
Last active January 22, 2020 22:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tokland/c0db1473cc9bfa924470e52bdac8450c to your computer and use it in GitHub Desktop.
Save tokland/c0db1473cc9bfa924470e52bdac8450c to your computer and use it in GitHub Desktop.
Typescript: Pattern-matching for tagged unions (match only by discriminator tag)
export type Matcher<KindField extends string, Kind extends string, Obj, Result> = {
[K in Kind]: (obj: Extract<Obj, { [F in KindField]: K }>) => Result;
};
export function match<KindField extends string>(field: KindField) {
return function<
Obj extends { [K in KindField]: Kind },
Result,
Kind extends string = Obj[KindField]
>(obj: Obj, matcher: Matcher<KindField, Kind, Obj, Result>): Result {
const fn = matcher[obj[field]];
return fn(obj as Parameters<typeof fn>[0]);
};
}
// Example
const matchByKind = match("kind");
type Square = { kind: "square"; side: number };
type Circle = { kind: "circle"; radius: number };
type Shape = Square | Circle;
const shape = { kind: "square", side: 2 } as Shape;
const surface = matchByKind(shape, {
square: square => square.side ** 2,
circle: circle => Math.PI * circle.radius ** 2,
});
console.log(surface.toFixed());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment