打字稿:将带标签的联合转换为联合类型

时间:2020-06-26 08:49:14

标签: typescript union-types

我具有以下标记的联合界面

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

作为输出,我想将此标记的联合转换为联合类型,例如:

type oneOf<T> = ...

哪里

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

我无法将类型键映射到仅具有键作为参数的对象中。有什么主意吗?

2 个答案:

答案 0 :(得分:2)

您可以通过以下方式组合使用:

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>

这将返回预期结果:

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

以上内容正确无误,但TS允许以下操作

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

这不是我们通常想要的:

以下是用于更严格的类型检查的变体

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

查看问题:

答案 1 :(得分:0)

type EntryUnion<T> = { [K in keyof T]: { [Q in K]: T[Q] } }[keyof T];

这实际上与

相同
type EntryUnion<T> = { [K in keyof T]: Pick<T, K> }[keyof T];

但是每当我使用诸如 Pick 之类的 util 类型时,Intellij 和 VS Code 中的类型推断都会在 Pick 处停止并拒绝进一步扩展。尽管他们在强制分配人员的类型正确性方面做着完全相同的工作,但当出现问题时,使用 Pick 的类型定义不正确的地方就不那么明显了(除非您非常熟悉 Pick 的功能)