有没有办法像这样改变一个受歧视的联盟:
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
。
答案 0 :(得分:1)
TypeScript缺少一些type operators,你需要做你想做的事。您喜欢能够说出类似的内容:
type DiscUnionToObject<U extends MyUnion> = {
[V in U['type']]: (U & { type: V })['values']
}
其中(U & { type: V })
交叉点会剔除被区分联合的单个元素。例如,如果U
为Something
且V
为part
,那么我们就会谈论(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';
}