【问题标题】:Turning discriminated union into object将有区别的联合变成对象
【发布时间】:2018-06-27 13:25:30
【问题描述】:

有没有办法像这样转变受歧视的工会:

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&lt;Something&gt; 时,它会产生

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

type 设置为mode 时,我无法找到一种方法让泛型类型“理解”'upper' | 'lower' 不是Something 的一部分。

【问题讨论】:

  • 我很好奇这个用例是什么?
  • @Aaron 我正在尝试从styled-theming 库中为theme 函数编写一个类型,在此过程中我偶然发现了这个问题。我不确定它是否可以帮助我达到预期的效果,但我也很好奇是否有人可以做这样的事情。

标签: typescript types typescript2.0


【解决方案1】:

TypeScript 缺少一些 type operators 你需要做你想做的事。你会喜欢能够说这样的话:

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

(U &amp; { type: V }) 的交集将提取出可区分联合的单个元素。例如,如果USomethingVpart,那么我们讨论的是(Something &amp; { type: 'part' }),它道德 等同于{type: 'part', values: 'upper'|'lower'},但是编译器不承认这一点:它必须说'part'&amp;'mode'never,并且任何具有never-valued 属性的对象本身就是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 是否与您原来的相同。希望有帮助;祝你好运!

【讨论】:

  • 其实反其道而行之对我也有好处!非常感谢,尤其是第二部分!
【解决方案2】:

自 Typescript 2.8 以来,有可能“提取”可区分联合的单个组件:

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

多亏了这一点,现在可以完全按照最初的意图去做:

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

使用这种类型,当我们执行DiscUnionToObject&lt;Something&gt; 时,我们会得到我们想要的:

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

【讨论】:

    猜你喜欢
    • 2015-01-24
    • 2015-05-24
    • 1970-01-01
    • 2021-02-14
    • 2021-11-19
    • 2018-11-24
    • 1970-01-01
    • 2015-02-27
    相关资源
    最近更新 更多