将受歧视的联盟变成对象
Turning discriminated union into object
有没有办法让受歧视的工会变成这样:
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';
}
当 type
设置为 [=18= 时,'upper' | 'lower'
不是 Something
的一部分,我找不到通用类型 "understand" 的方法].
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' }
) 等同于 {type: 'part', values: 'upper'|'lower'}
,但编译器无法识别这一点:它必须说 'part'&'mode'
是 never
,并且任何带有 never
- 的对象valued 属性 本身就是 never
,但这些减少都没有发生(嗯,不是我们需要的地方)。
所以你不能那样做。您还希望能够迭代联合 and/or 交集并映射每个元素以生成其他联合 and/or 交集,这是映射类型的更通用版本。但你也不能那样做。
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
是否与您原来的相同。希望有所帮助;祝你好运!
自 Typescript 2.8 以来,有可能 "pluck out" 可区分联合的单个组件:
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';
}
有没有办法让受歧视的工会变成这样:
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';
}
当 type
设置为 [=18= 时,'upper' | 'lower'
不是 Something
的一部分,我找不到通用类型 "understand" 的方法].
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' }
) 等同于 {type: 'part', values: 'upper'|'lower'}
,但编译器无法识别这一点:它必须说 'part'&'mode'
是 never
,并且任何带有 never
- 的对象valued 属性 本身就是 never
,但这些减少都没有发生(嗯,不是我们需要的地方)。
所以你不能那样做。您还希望能够迭代联合 and/or 交集并映射每个元素以生成其他联合 and/or 交集,这是映射类型的更通用版本。但你也不能那样做。
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
是否与您原来的相同。希望有所帮助;祝你好运!
自 Typescript 2.8 以来,有可能 "pluck out" 可区分联合的单个组件:
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';
}