区分联合类型的类型属性
Type properties to discriminated union types
我想将一个类型转换为可区分的联合类型:
type Current = {
A : number,
B : string,
}
到
type Target= {
type: 'A',
value: number
}
| {
type: 'B',
value: string
}
这样我就可以区分结果了。
function handle(result: ToTarget<Current>) {
switch(result.type){
case 'A':
return result.value // number
case 'B':
return result.value // string
}
}
我得到的最接近的是:
type ToTargetA<U> = { code: keyof U, value : U[keyof U] }
// code and value are not in sync so code is 'A | B' and value is 'number | string' but discriminating on code does not narrow value.
type ToTargetB<U, K extends keyof U = any> = { code: keyof K, value : U[K] }
// requires me to specify K as a generic parameter which is not what I want.
我尝试了几种条件类型表达式,但无法更接近。
这可行,但想知道是否有 cleaner/better 解决方案。
type DistributedProperties<T> = { [P in keyof T] : { code: P, value: T[P]} }
type Union<T> = DistributedProperties<T>[keyof DistributedProperties<T>]
这是一种方法:
type ToDiscriminatedUnion<T, KK extends PropertyKey, VK extends PropertyKey> =
{ [K in keyof T]: { [P in KK | VK]: P extends KK ? K : T[K] } }[keyof T];
您可以验证它生成了您想要的类型:
type Target = ToDiscriminatedUnion<Current, 'type', 'value'>;
/* type Target = {
type: "A";
value: number;
} | {
type: "B";
value: string;
} */
此处的方法是使用与原始对象类型 T
中相同的键 K
构建一个 mapped type,但其值是您的 {type: T, value: T[K]}
类型想要在受歧视的联盟中。这种类型最终变成 {A: {type: "A", value: number}, B: {type: "B". value: string}}
.
然后我们可以 look up 其 属性 值的联合,通过使用 [keyof T]
对其进行索引,生成所需的 {type: "A", value: string} | {type: "B", value: number}
可区分联合。
我在那里做的唯一额外的事情就是制作它,这样你就可以指定给原始键名(KK
,在你的情况下是 "type"
)和原始值的键名称(VK
,在您的情况下为 "value"
)。如果你不想改变它,你可以硬编码它:
type ToDiscriminatedUnion<T> =
{ [K in keyof T]: { type: K, value: T[K] } }[keyof T];
type Target = ToDiscriminatedUnion<Current>;
我想将一个类型转换为可区分的联合类型:
type Current = {
A : number,
B : string,
}
到
type Target= {
type: 'A',
value: number
}
| {
type: 'B',
value: string
}
这样我就可以区分结果了。
function handle(result: ToTarget<Current>) {
switch(result.type){
case 'A':
return result.value // number
case 'B':
return result.value // string
}
}
我得到的最接近的是:
type ToTargetA<U> = { code: keyof U, value : U[keyof U] }
// code and value are not in sync so code is 'A | B' and value is 'number | string' but discriminating on code does not narrow value.
type ToTargetB<U, K extends keyof U = any> = { code: keyof K, value : U[K] }
// requires me to specify K as a generic parameter which is not what I want.
我尝试了几种条件类型表达式,但无法更接近。
这可行,但想知道是否有 cleaner/better 解决方案。
type DistributedProperties<T> = { [P in keyof T] : { code: P, value: T[P]} }
type Union<T> = DistributedProperties<T>[keyof DistributedProperties<T>]
这是一种方法:
type ToDiscriminatedUnion<T, KK extends PropertyKey, VK extends PropertyKey> =
{ [K in keyof T]: { [P in KK | VK]: P extends KK ? K : T[K] } }[keyof T];
您可以验证它生成了您想要的类型:
type Target = ToDiscriminatedUnion<Current, 'type', 'value'>;
/* type Target = {
type: "A";
value: number;
} | {
type: "B";
value: string;
} */
此处的方法是使用与原始对象类型 T
中相同的键 K
构建一个 mapped type,但其值是您的 {type: T, value: T[K]}
类型想要在受歧视的联盟中。这种类型最终变成 {A: {type: "A", value: number}, B: {type: "B". value: string}}
.
然后我们可以 look up 其 属性 值的联合,通过使用 [keyof T]
对其进行索引,生成所需的 {type: "A", value: string} | {type: "B", value: number}
可区分联合。
我在那里做的唯一额外的事情就是制作它,这样你就可以指定给原始键名(KK
,在你的情况下是 "type"
)和原始值的键名称(VK
,在您的情况下为 "value"
)。如果你不想改变它,你可以硬编码它:
type ToDiscriminatedUnion<T> =
{ [K in keyof T]: { type: K, value: T[K] } }[keyof T];
type Target = ToDiscriminatedUnion<Current>;