微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

类型属性以区分的联合类型

如何解决类型属性以区分的联合类型

我想将类型转换为可区分的联合类型:

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.

我尝试了几种条件类型表达式,但相距甚远。

解决方法

这里是一种方法:

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;
} */

此处的方法是使用与原始对象类型K中相同的键T构建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>;

Playground link to code

,

这可行,但是想知道是否有更干净/更好的解决方案。

type DistributedProperties<T> = { [P in keyof T] : { code: P,value: T[P]} } 
type Union<T> = DistributedProperties<T>[keyof DistributedProperties<T>]

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。