是否可以在区分联合类型上定义类似通用匹配函数的内容? 假设我们有以下类型定义:
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
}
使用switch语句可以定义匹配函数,如:
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);
}
}
}
它完成了这项工作,但定义这些功能非常繁琐,尤其是当一个人有很多工会成员时。
是否有可能以某种方式简化此定义,可能使用Mapped Types或来自最新2.1分支的其他现有方法。
我正在玩“Mapped Types”,但即使我知道 Kind ,我也不确定实际上是否有可能获得具体的 Value ,例如像:
type Matcher<T> = {[P in Kind]: (value: P) => T};
function match<T>(matcher: Matcher<T>) {
return function(value: Value) {
return matcher[value.kind](value);
}
}
但实际上可以将 P 转换为相应的值类型。
答案 0 :(得分:0)
关键在于能够根据工会的类型获得工会的成员。可以用这样的类型来完成:
type UnionMemberByKind<K> = Extract<Union, { kind: K }>
Extract<T, U>
返回与T
匹配的U
的成员:在这种情况下,它将返回具有指定的kind
的并集的单个成员。
使用该类型,您可以正确构建匹配器对象:
type Matcher<Res> = {
[P in Union["kind"]]: (value: UnionMemberByKind<P>) => Res
}
然后基本上像以前一样定义您的匹配函数:
function match<T>(matcher: Matcher<T>) {
return function(value: Union) {
return matcher[value.kind](value as any);
}
}
(不幸的是as any
演员表,但我找不到避免这种情况的方法)