如何展平对象的并集类型

时间:2019-05-24 18:37:19

标签: typescript

我具有以下联合类型:

type Test =
  | {
      type: 'Union'
      items: Array<
        | { type: 'Number' }
        | { type: 'String' }
        | { type: 'Union'; items: Array<{ type: 'Number' } | { type: 'Boolean' }> }
      >
    }
  | { type: 'Date' }

我希望结果是:

type Result = 
  | { type: 'Number' }
  | { type: 'String' }
  | { type: 'Boolean' }
  | { type: 'Date' }

由于循环引用的限制,以下内容无效:

type Flatten<T> = T extends { type: 'Union'; items: unknown[] }
                  ? Flatten<T['items'][number]>
                  : T

是否可以使用接口或其他替代方法来解决?

1 个答案:

答案 0 :(得分:2)

据我所知(截至TS3.5),no supported technique通常会执行递归条件类型函数。通常,如果圆度涉及将类型下推到嵌套属性中,但是不支持将类型 out 拉出嵌套属性,则可以。我尝试过(或看过尝试过)欺骗编译器接受这些事情的所有“聪明”技巧都以悲伤告终。

通常,当我想要一个像这样的递归类型时,我要做的是选择某种合理的递归深度来进行纾困。在这种情况下,您期望T通常位于Flatten<T>中的嵌套深度是多少……假设最多六层?好吧,在这种情况下,我们可以将圆形类型展开为一系列非圆形类型,这些类型最终会碰到砖墙:

type Flatten<T> = T extends { type: 'Union'; items: unknown[] } ? Flatten1<T['items'][number]> : T;
type Flatten1<T> = T extends { type: 'Union'; items: unknown[] } ? Flatten2<T['items'][number]> : T;
type Flatten2<T> = T extends { type: 'Union'; items: unknown[] } ? Flatten3<T['items'][number]> : T;
type Flatten3<T> = T extends { type: 'Union'; items: unknown[] } ? Flatten4<T['items'][number]> : T;
type Flatten4<T> = T extends { type: 'Union'; items: unknown[] } ? Flatten5<T['items'][number]> : T;
type Flatten5<T> = T extends { type: 'Union'; items: unknown[] } ? Flatten6<T['items'][number]> : T;
type Flatten6<T> = T extends { type: 'Union'; items: unknown[] } ? FlattenX<T['items'][number]> : T;
type FlattenX<T> = T; // uh oh  bail out

这可能很丑陋,但通常效果可控。让我们看看它如何处理您的类型:

type Result = Flatten<Test>;
// type Result = { type: "Date"; } | { type: "Number"; } | 
// { type: "String"; } | { type: "Number"; } | { type: "Boolean"; }

对我很好。好的,希望对您有所帮助。祝你好运!

Link to code