Is it possible to define something like a generic match function over discriminated union type? Let's say we have the following type definitions:
const Kinds = {
A: 'A',
B: 'B',
};
type Kind = typeof Kinds.A | typeof Kinds.B;
type Value = A | B;
interface A {
kind: Kinds.A
}
interface B {
kind: Kinds.B
}
With switch statement it is possible to define match function like:
interface Matcher<T> {
Kinds.A: (value: A) => T
Kinds.B: (value: B) => T
}
function match<T>(matcher: Matcher<T>) {
return function(value: Value) {
switch (value.kind) {
case Kinds.A: return matcher[Kinds.A](value);
case Kinds.B: return matcher[Kinds.B](value);
}
}
}
It does the job, but it is very tedious to define such functions especially when one have many union members.
Is it possible to simplify this definition somehow, maybe with Mapped Types or other existing means from the latest 2.1 branch.
I was playing around with "Mapped Types", but I'm not sure that it is actually possible to get concrete Value even when I know Kind, e.g something like:
type Matcher<T> = {[P in Kind]: (value: P) => T};
function match<T>(matcher: Matcher<T>) {
return function(value: Value) {
return matcher[value.kind](value);
}
}
but where one can actually translate P to corresponding Value type.