Skip to content

Instantly share code, notes, and snippets.

@bmingles
Last active April 20, 2020 15:31
Show Gist options
  • Save bmingles/4a1e9195fabe45a60ef559897724541b to your computer and use it in GitHub Desktop.
Save bmingles/4a1e9195fabe45a60ef559897724541b to your computer and use it in GitHub Desktop.
TypeScript tagged union matching with exahaustive checking
/**
* Map discriminated union based on its tag value.
* Possible tag values are mapped to expressions
* that return a transformation of the original value.
* Each value is exhaustive checked such that a mapping
* has to be provided for each one.
*
* e.g.
*
* type Union =
* | { tag: 'aaa', value: string }
* | { tag: 'bbb', createdAt: Date }
*
* declare const union: Union;
*
* // number | Date
* const result = match(union, {
* aaa: ({ value }) => value.length,
* bbb: ({ createdAt }) => createdAt
* })
*/
function match<
T extends { tag: string },
M extends { [P in T['tag']]: T extends { tag: P } ? (t: T) => any : never },
>(
value: T,
map: M
): ReturnType<M[keyof M]> {
return map[value.tag as keyof M](value)
}
/** Example usage */
type Union =
| { tag: 'aaa', value: string }
| { tag: 'bbb', createdAt: Date }
declare const union: Union;
// number | Date
const result = match(
union,
{
aaa: ({ value }) => value.length,
bbb: ({ createdAt }) => createdAt
}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment