【问题标题】:how to write an `Invert` type in typescript to invert the order of tuples如何在打字稿中编写“反转”类型以反转元组的顺序
【发布时间】:2020-01-09 06:47:01
【问题描述】:
type a = [1,2,3]
type Invert<T extends any[] & {'0': any}> = ???
type b = Invert<a> // should yield [3,2,1]

我一直想弄清楚元组的Invert 类型的定义, 也是 InitLast 类型,尽管它们可能由彼此构成

我尝试过的:

  1. 在函数参数定义中定位类型并推断Rest 部分,这种方法只得到了带有其余参数的Tail 部分

【问题讨论】:

    标签: typescript tuples type-level-computation


    【解决方案1】:

    从打字稿 4.0 开始 接近 Reverse 类型的代码比以前容易得多,说

    type Reverse<T extends any[], R extends any[] = []> =  ReturnType<T extends [infer F, ...infer L] ? () => Reverse<L,[F,...R]> : () => R>
    

    一些解释:

    1. 在 typealias Reverse 中直接引用类型 Reverse 会导致循环引用错误。
    2. 在函数类型 (()=&gt; Reverse) 中包装 Reverse 类型将退出循环引用错误
    3. 如果类型表达式可以静态解析,编译器会尝试解析它,所以ReturnType&lt;() =&gt; Tup&lt;L,[F,...R]&gt;&gt; 不会解决问题,但是 ReturnType&lt;ConditionalType&gt; 会的

    【讨论】:

    • 你是个天才!谢谢!
    【解决方案2】:

    TypeScript 4.1 引入了递归条件类型。

    它们允许像这样实现元组反转函数:

    type Reverse<Tuple> = Tuple extends [infer Head, ...infer Rest]
           ? [...Reverse<Rest>, Head] : [];
    
    const test: Reverse<[1,2,3,4]> = [4,3,2,1];
    

    【讨论】:

    • 感谢您的回答。我没想过只是传播递归调用的结果。好主意,我肯定会更频繁地使用这种方法。
    【解决方案3】:

    这只有在你知道数组的长度时才有效:

    type a = [1,2,3]
    type Invert<T extends [any, any, any]> = [T[2], T[1], T[0]];
    type b = Invert<a> // should yield [3,2,1]
    

    更新

    其实有一个解决方案(在 typescript 项目的问题上找到here):

    export type Prepend<Tuple extends any[], Addend> = 
         ((_: Addend, ..._1: Tuple) => any) extends ((..._: infer Result) => any) ? Result : never;
        
    export type Reverse<Tuple extends any[], Prefix extends any[] = []> = {
        0: Prefix;
        1: ((..._: Tuple) => any) extends ((_: infer First, ..._1: infer Next) => any)
            ? Reverse<Next, Prepend<Prefix, First>>
            : never;
    }[Tuple extends [any, ...any[]] ? 1 : 0];
    
    
    type b = Reverse<[1, 2, 3]>; // type b = [3, 2, 1]
    
    

    Playground Link

    【讨论】:

    • 其实我想要一个通用的版本
    • 如果您的意思是反转任意数量的数组条目的类型定义,这是不可能的。正如您上面提到的,这需要一个头尾运算符,而这又需要一个休息运算符以及通用约束的递归。两者都不存在于泛型中。
    • @Minami 我最后的评论不是真的,存在一个通用版本。请参阅我的更新答案。
    • @1y1nq 不错的解决方案
    猜你喜欢
    • 2013-06-15
    • 1970-01-01
    • 2020-01-17
    • 1970-01-01
    • 2020-06-30
    • 2021-11-17
    • 1970-01-01
    • 2010-12-13
    • 2011-12-18
    相关资源
    最近更新 更多