semlinker/awesome-typescript

「重学TS 2.0 」TS 练习题第二十七题

semlinker opened this issue · 14 comments

实现一个 Reverse 工具类型,用于对元组类型中元素的位置颠倒,并返回该数组。元组的第一个元素会变成最后一个,最后一个元素变成第一个。

type Reverse<
  T extends Array<any>,
  R extends Array<any> = []
> = // 你的实现代码

type R0 = Reverse<[]> // []
type R1 = Reverse<[1, 2, 3]> // [3, 2, 1]

请在下面评论你的答案。

suica commented
type Reverse<
  T extends Array<any>,
  R extends Array<any> = []
> = T extends [infer A,... infer B]? Reverse<B,[A,...R]> : R 

type R0 = Reverse<[]> // []
type R1 = Reverse<[1, 2, 3]> // [3, 2, 1]
type Reverse<
  T extends Array<any>
> = T extends [infer First, ...infer Rest] ? [...Reverse<Rest>, First] : []

type R0 = Reverse<[]> // []
type R1 = Reverse<[1, 2, 3]> // [3, 2, 1]
type Reverse<T extends Array<any>> = T extends [infer First, ...infer Rest]
  ? [...Reverse<Rest>, First]
  : [];

type R0 = Reverse<[]>; // []
type R1 = Reverse<[1, 2, 3]>; // [3, 2, 1]
type Push<T extends any[], V> =  [...T, V];

type Reverse<
  T extends Array<any>,
  R extends Array<any> = []
> = T extends [infer A, ...infer K] ? K extends [] ? Push<R, A> : Push<Reverse<K, R>, A> : []

type R0 = Reverse<[]> // []
type R1 = Reverse<[1, 2, 3]> // [3, 2, 1]

向下递归时,变换一下两个 infer 变量的位置即可

type Reverse<T extends any[]> = T extends [infer R1, ...infer R2] ? [...Reverse<R2>, R1] : []

type R0 = Reverse<[]> // []
type R1 = Reverse<[1, 2, 3]> // [3, 2, 1]
type Reverse<
  T extends Array<any>,
  R extends Array<any> = []
> = T extends [infer F, ...infer B] ? Reverse<B, [F, ...R]> : R// Reverse<B, [F, ...R]>就将前面的类型放置于后面

type R0 = Reverse<[]> // []
type R1 = Reverse<[1,2,3]> // [3,2,1]

题解

这里采用递归方式,每次递归都把第一项 First 放在最后,并把递归结果展开:

type Reverse<T extends Array<any>> = 
  T extends [infer First, ...infer Rest]
  ? [...Reverse<Rest>, First]
  : [];

type R0 = Reverse<[]> // []
type R1 = Reverse<[1, 2, 3]> // [3, 2, 1]
type R2 = Reverse<[1, 2, 3, 4, 5]> //  [5, 4, 3, 2, 1]

拓展

本题还可以引入一个空数组暂存结果:

type Reverse<
  T extends Array<any>,
  A extends Array<any> = []
> = T extends [infer First, ...infer Rest] ?  Reverse<Rest, [First, ...A]> : A;

第一次执行的时候,把 T 分成第一项 First 和剩余的 Rest,每次递归的时候,把 First 和暂存数组 A 合并,作为递归的第二个参数,即上一步翻转的结果,到最后返回暂存数组 A 即可。

类似的还可以这么处理:

type Reverse<
  T extends Array<any>,
  A extends Array<any> = []
> = T extends [...infer Rest, infer Last] ?  
    A['length'] extends T['length'] ? A :
    Reverse<Rest, [...A, Last]> : A;

type R0 = Reverse<[]> // []
type R1 = Reverse<[1, 2, 3]> // [3, 2, 1]
type R2 = Reverse<[1, 2, 3, 4, 5]> //  [5, 4, 3, 2, 1]
type Reverse<
T extends Array<any>,
R extends Array<any> = []
> = T extends [infer A, ...infer B]
  ? [...Reverse<B>, A]
  : [];

type R0 = Reverse<[]> // []
type R1 = Reverse<[1, 2, 3]> // [3, 2, 1]

这类型的问题,着眼点都在数组的形状上。

type Reverse<T extends Array<any>, R extends Array<any> = []> = T extends [...infer A, infer B] ? [B, ...Reverse<A>] : [];

type R0 = Reverse<[]>; // []
type R1 = Reverse<[1, 2, 3]>; // [3, 2, 1]
type Reverser<
  T extends Array<any>,
  R extends Array<any> = []
> = T extends [infer F, ...infer Rest]
    ? Reverser<Rest, [F,...R]>
    : R

type R0 = Reverser<[]>
type R1 = Reverser<[1,2,3,4,5]>
type R0 = Reverse<[]> // []
type R1 = Reverse<[1, 2, 3, 4, 5]> // [3, 2, 1]

type Reverse<
  T extends Array<any>,
  R extends Array<any> = []
> =
  T extends [infer First, ...infer Rest]
    ? Reverse<Rest, [First, ...R]>
    : R
  type Reverse<
    T extends Array<any>,
    R extends Array<any> = []
  > = T extends [infer First, ...infer Rest] ? Reverse<Rest, [First, ...R]> : R
type Reverse<
  T extends Array<any>,
  R extends Array<any> = []
> = T extends [] ? R : (
  T extends [infer First, ...infer Rest] ? Reverse<Rest, [First, ...R]> : R
)
type Reverse<
  T extends Array<any>,
  R extends any[] = [],
> = T extends [infer A, ...infer Rest]
  ? Reverse<[...Rest], [A, ...R]>
  : R