Last active
January 22, 2020 22:23
-
-
Save tokland/c0db1473cc9bfa924470e52bdac8450c to your computer and use it in GitHub Desktop.
Typescript: Pattern-matching for tagged unions (match only by discriminator tag)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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