Typescript: convert a tagged union into an union type

和自甴很熟 提交于 2021-02-04 20:58:12

问题


I've the following tagged union interface

interface Example {
  a: TypeA;
  b: TypeB;
}

as an output I would like to convert this tagged union into an union type such as:

type oneOf<T> = ...

Where

var example: oneOf(Example); // would be { a: TypeA } | { b : TypeB }

I have not been able to map the type keys into an object having only the key as parameter. Any idea ?


回答1:


You can do it with a combination of:

  • Distributive conditional types
  • Mapped types
interface Example {
  a: string;
  b: number;
}

type SingleProperty<T, K extends keyof T> = K extends any ? {[Prop in K]: T[Prop]} : never
type UnionOfProperties<T> = { [K in keyof T]: SingleProperty<T, K> }[keyof T];
type ExamplePropertiesUnion = UnionOfProperties<Example>

This returns expected:

type ExamplePropertiesUnion = {
    a: string;
} | {
    b: number;
}

While the above is correct, TS will allow the following

var t: ExamplePropertiesUnion = {a: "", b: 42}

Which is NOT what we usually want:

Here below is the variant for a stricter type checking

type FixTsUnion<T, K extends keyof T> = {[Prop in keyof T]?: Prop extends K ? T[Prop]: never}
type oneOf<T> = { [K in keyof T]: Pick<T, K> & FixTsUnion<T, K>}[keyof T];
// ok
var z1: oneOf<Example> = { a: "" };
// ok
var z2: oneOf<Example> = { b: 5 };
// error
var z3: oneOf<Example> = { a: "", b: 34 };
// error
var z4: oneOf<Example> = { };

Try it here

See questions:

  • TypeScript: Map union type to another union type
  • Transform union type to intersection type


来源:https://stackoverflow.com/questions/62591230/typescript-convert-a-tagged-union-into-an-union-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!