【问题标题】:How to get a flattened tuple type of a tuple of tuples?如何获得元组元组的扁平元组类型?
【发布时间】:2020-08-24 19:59:23
【问题描述】:

假设我有一个元组:

type Example = [[3,5,7], [4,9], [0,1,10,9]];

我想创建一个实用程序类型 Flatten<T> 这样Flatten<Example> 给出:

type FlatExample = Flatten<Example>;
// type FlatExample = [3,5,7,4,9,0,1,10,9];

对于我的用例,您可以假设元组只嵌套了一层。元组可以有任意大小。

我该怎么做?

【问题讨论】:

    标签: typescript tuples recursive-type


    【解决方案1】:

    为此,您需要递归条件类型。这将在 4.1 中得到完全支持:

    type Example = [[3,5,7], [4,9], [0,1,10,9]];
    type Flatten<T extends any[]> = 
        T extends [infer U, ...infer R] ? U extends any[] ? [...U, ... Flatten<R>]: []: []
    type FlatExample = Flatten<Example>;
    

    Playground Link

    编辑

    更简单的版本,jcalz 的屈尊:

    type Example = [[3,5,7], [4,9], [0,1,10,9]];
    type Flatten<T extends any[]> = 
        T extends [any, ...infer R] ? [...T[0], ... Flatten<R>]:  []
    type FlatExample = Flatten<Example>;
    

    Playground Link

    /编辑

    即使在今天你也可以破解一个版本(需要额外的间接来欺骗编译器以允许递归条件类型,从概念上讲这相当于上面更简单的版本):

    type Example = [[3, 5, 7], [4, 9], [0, 1, 10, 9]];
    type Flatten<T extends any[]> = T extends [infer U, ...infer R] ? {
        1: U extends any[] ? [...U, ...Flatten<R>] : [],
        2: []
    }[U extends any[] ? 1 : 2] : [];
    
    type FlatExample = Flatten<Example>;
    
    

    Playground Link

    只是为了好玩,4.1,通用扁平化版本。

    type Example = [[3,5,7], [4,9, [10, 12, [10, 12]]], [0,1,10,9, [10, 12]]];
    type Flatten<T extends any[]> = 
        T extends [infer U, ...infer R] ? 
            U extends any[] ? 
            [...Flatten<U>, ... Flatten<R>]: [U, ... Flatten<R>]: []
    type FlatExample = Flatten<Example>;
    

    Playground Link

    注意:虽然递归类型在 4.1 中得到更多支持,但您仍然会遇到编译器硬编码的限制,例如类型实例化深度和类型实例总数(因为递归类型会生成大量类型实例化)。所以请谨慎使用。

    【讨论】:

    • 该死,你先来了。 4.1 的真正递归条件类型!
    • @jcalz 我一直在寻找这样的答案?。这是 ts 类型系统的激动人心的时刻?
    • 我自己可能会选择type Flatten&lt;T&gt; = T extends [any, ...infer R] ? [...T[0], ...Flatten&lt;R&gt;] : [],但这个也可以
    • @jcalz 也添加了那个版本,你说得对,它更简单:)
    • @jcalz 我想通了。这是 Prettier 的问题。它正在将 ...infer R 更改为 ...(infer R),即使在新的 2.1.0 版本中也是如此。我现在使用// prettier-ignore 评论来禁用它。谢谢大家的关注! :)
    猜你喜欢
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    • 2018-04-11
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    相关资源
    最近更新 更多