根据字段映射联合类型

时间:2020-04-11 11:55:22

标签: typescript

我有一个联合类型,每个子类型都有一个“类型”字段。我想自动构建一个类型,其字段是“ type”的不同值,并且这些值分别是相应子类型的数组。不知道这是否清楚,但是此示例会有所帮助:

// What I have :

type A = { type: "A" };
type B = { type: "B" };
type C = { type: "C" };
type MyUnion = A | B | C;

// What I want automatically generated :

type Keyed = {
  A: A[];
  B: B[];
  C: C[];
};

是否有一种方法可以做到 而无需 ,只需给定A即可手动将“ A”映射到类型MyUnion等? / p>

我想到了类似的东西:

type Keyed = {
  [T in MyUnion["type"]]: ??
};

但是我不知道如何基于MyUnionT拆分为各个子类型。

1 个答案:

答案 0 :(得分:1)

我认为这是做到这一点的方法:

type Keyed<T extends MyUnion> = {
    [P in T["kind"]]: T extends (infer U)
        ? T["kind"] extends P
            ? U[] : never
        : never
}

但是很复杂。也许手动编写Keyed类更容易阅读。

需要使用束缚的extends语句,因为您想不确定数组中没有不同类型的混合。例如,编译器会警告您这一点,因为在“ A”数组中有“ A”和“ B”类型:

var c: Keyed<MyUnion> = {
    "A": [{ kind: "A" }, { kind: "B" }], // Error on 2nd item, bacause "B"
    "B": [{ kind: "B" }],
    "C": []
}

这是有效数据:

var c: Keyed<MyUnion> = {
    "A": [{ kind: "A" }, { kind: "A" }],
    "B": [{ kind: "B" }],
    "C": []
}

我将属性type重命名为kind。它符合TypeScript文档中的约定,并避免了使用关键字type作为属性名称的混淆。