将歧视联盟转变为客体

时间:2018-01-18 12:53:49

标签: typescript types typescript2.0

有没有办法像这样改变一个受歧视的联盟:

type Something = {
   type: 'mode';
   values: 'first' | 'second';
} | {
   type: 'part';
   values: 'upper' | 'lower';
};

{
    mode: 'first' | 'second';
    part: 'upper' | 'lower';
}

使用某种通用类型?

到目前为止,我尝试过这样的事情:

type MyUnion = {
   type: string;
   values: string;
};

type DiscUnionToObject<U extends MyUnion> = {
   [V in U['type']]: U['values']
}

但当我做DiscUnionToObject<Something>时它会产生

{
    mode: 'first' | 'second' | 'upper' | 'lower';
    part: 'first' | 'second' | 'upper' | 'lower';
}

我无法找到通用类型的方式来理解&#34;当'upper' | 'lower'设置为Something时,type不属于mode

2 个答案:

答案 0 :(得分:1)

TypeScript缺少一些type operators,你需要做你想做的事。您喜欢能够说出类似的内容:

type DiscUnionToObject<U extends MyUnion> = {
  [V in U['type']]: (U & { type: V })['values']
}

其中(U & { type: V })交叉点会剔除被区分联合的单个元素。例如,如果USomethingVpart,那么我们就会谈论(Something & { type: 'part' }道德< / em>等同于{type: 'part', values: 'upper'|'lower'},但编译器无法识别:它必须说'part'&'mode'never,并且任何具有never值的对象属性本身是never,但这些减少都不会发生(好吧,不是我们需要它的地方)。

所以你不能这样做。您还希望能够遍历联合和/或交叉点并映射每个元素以生成其他联合和/或交叉点,这是映射类型的更一般版本。但你也做不到。

TypeScript在编程生成有区别的联合比在编程分析它们时要好得多。因此,根据您的使用情况,您可以反过来提出要求。从对象开始并生成联合:

type SomethingObject = {
  mode: 'first' | 'second'
  part: 'upper' | 'lower'
}

type ObjectToDiscUnion<O, V = {
  [K in keyof O]: {type: K, values: O[K]}
}> = V[keyof V]

type Something = ObjectToDiscUnion<SomethingObject>;

您可以验证上面的Something是否与原始版本相同。希望有所帮助;祝你好运!

答案 1 :(得分:0)

自从Typescript 2.8 ,有可能&#34;拔出&#34;受歧视的工会的单一组成部分:

Extract<P, { type: 'mode' }>;

由于这一点,现在可以完全按照预期的方式完成:

type DiscUnionToObject<U extends MyUnion> = {
    [V in U['type']]: Extract<U, { type: V }>['values'];
}

使用此类型,当我们执行DiscUnionToObject<Something>时,我们会得到我们想要的内容:

{
    mode: 'first' | 'second';
    part: 'upper' | 'lower';
}