作为this answer的后续工作,我正在尝试编写一个泛型类型,该类型将标记映射到作为区分联合的一部分的类型。
上述答案中给出的通用版本有效:
type DiscriminateUnion<T, K extends keyof T, V extends T[K]> = T extends Record<K, V> ? T : never
但是我不能自己制作一个不通用的版本。如果我使用默认的联合类型泛型,我觉得很奇怪。
这是我的代码:

interface TypeA {
  tag: "a";
  data: string;
}

interface TypeB {
  tag: "b";
  data: [number];
}

interface TypeCD {
  tag: "c" | "d";
  data: number;
}

type Union = TypeA | TypeB | TypeCD;

type DiscriminatedUnion_0<V extends Union["tag"]> = Union extends Record<"tag", V> ? Union : never;
let shouldBeTypeA_0: DiscriminatedUnion_0<"a">; // doesn't work, type 'never'

// this works
type DiscriminatedUnion_1<V extends Union["tag"], T extends Union = Union> = T extends Record<"tag", V> ? T : never;
let shouldBeTypeA_1: DiscriminatedUnion_1<"a">;

type DiscriminatedUnion_2<V extends Union["tag"], T extends Union> = T extends Record<"tag", V> ? T : never;
let shouldBeTypeA_2: DiscriminatedUnion_2<"a", Union>;

最佳答案

DiscriminateUnion中的技术使用一个distributive conditional type仅在检查一个空泛型类型参数时才起作用。这个链接很好地解释了这一点,如果你想的话,你也可以阅读alonger explanation。获得此行为的唯一方法是在某个地方对一个裸露的泛型类型参数执行条件操作。这就是DiscriminatedUnion_1工作的原因;您检查了类型参数T
幸运的是,您不必玩默认类型参数的游戏来获得这种效果。必须进行泛型类型参数检查,但不必直接在最后的类型别名中。
一种方法是使用原始的DiscriminateUnion<T, K, V>定义并创建一个使用它的别名,比如

type MyDiscriminateUnion<V extends Union["tag"]> = DiscriminateUnion<Union, "tag", V>;

不过,另一种方法是使用名为Extract<T, U>的预定义类型别名in the standard library,它返回与另一个类型T匹配的联合类型U的所有组成部分。定义如下:
type Extract<T, U> = T extends U ? T : never;

这样,您就可以构造DiscriminatedUnion而不必使用默认类型参数玩游戏:
type DiscriminatedUnion<V extends Union["tag"]> = Extract<Union, Record<"tag", V>>;
let shouldBeTypeA: DiscriminatedUnion<"a">; // TypeA, hooray!

好吧,希望能帮上忙;祝你好运!

关于typescript - 将标签映射到已标记的工会成员不适用于特定工会,仅适用于通用工会,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55986469/

10-12 13:42