generics - Typescript 中区分联合类型的通用匹配函数

标签 generics typescript typescript2.1

是否可以在可区分的联合类型上定义类似通用匹配函数的东西? 假设我们有以下类型定义:

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 分支的其他现有方法。

我在玩“映射类型”,但我不确定是否真的有可能获得具体的Value,即使我知道Kind,例如某事喜欢:

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 转换为相应的 Value 类型。

最佳答案

这样做的关键是能够根据其种类获得工会成员。这可以用这样的类型来完成:

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 转换很不幸,但我找不到避免它的方法)

关于generics - Typescript 中区分联合类型的通用匹配函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40823398/

相关文章:

generics - F# 中序列表达式中的类型推断

generics - Kotlin - "where"通用约束问题

java - 通用最大 jSTL 函数

ajax - HttpClient Angular 5 不发送请求

TypeScript 2.1 自定义元素

node.js - 在编写自定义 TypeScript 定义文件时出现错误 "Module ' name'resolves to an untyped module at..."

java - java中如何调用使用泛型类型的类?

angular - 如何让 Angular Universal 为 Firebase Cloud Functions 编译 Typescript

typescript - 在 Typescript 中是否可以定义“字符串类型数组的对象”? (类型检查的正确位置?)

node.js - angular2中的导航错误