将联合转换为地图

时间:2017-10-14 14:44:58

标签: typescript types typescript2.0

让我们从这个给定的类型开始:

type Union =
  { type: 'A', a: string } |
  { type: 'B', b: number }

我希望我们在这里结束:

type MappedUnion = {
  A: { type: 'A', a: string }
  B: { type: 'B', b: number }
}

这是一些伪代码:

type MappedUnion<item in Union> = {[ i: item['type'] ]: item}

1 个答案:

答案 0 :(得分:1)

我认为你可以做到以下几点? Haven没有详尽地测试过,但似乎有效。

type Union =
  { type: 'A', a: string } |
  { type: 'B', b: number }

type MappedUnion = {[P in Union['type']]: Union & {type: P}};

const v: MappedUnion = {
  'A': {type: 'A', a: "hello"},
  'B': {type: 'B', b: 3},
}
可悲的是,没有相当的工作;如果我做

type MappedUnionTarget = {
  A: { type: 'A', a: string }
  B: { type: 'B', b: number }
}

function cvt1(x: MappedUnion): MappedUnionTarget {
  return x;
}

然后我得到Type '({ type: "A"; a: string; } & { type: "A"; }) | ({ type: "B"; b: number; } & { type: "A"; })' is not assignable to type '{ type: "A"; a: string; }'.我认为打字稿能够得出结论({ type: "B"; b: number; } & { type: "A"; })never相同。

如果您愿意使用Typescript 2.8(在撰写本文时,如果您使用TypeScript存储库中的git pull并且支持条件运算符? :,那么它是未发布的在类型级别)然后你似乎可以做

type FilterType<T, K> = (T extends { type: K } ? T : never);

type MappedUnion = {[P in Union['type']]: FilterType<Union, P>};

因为FilterType<T, K>是我希望T & {type: K}表现得像的事情。