类型体操入门:Slice

Extreme 难度的 Slice 过关了,终于可以自称类型体操入门了(喜)

题面

type-challenges/questions/00216-extreme-slice/README.md at main · type-challenges/type-challenges

Slice extreme array

by Anthony Fu @antfu

Take the Challgene

Implement the JavaScript Array.slice function in the type system. Slice<Arr, Start, End> takes the three argument. The output should be a subarray of Arr from index Start to End. Indexes with negative numbers should be counted from reversely.

For example

type Arr = [1, 2, 3, 4, 5];
type Result = Slice<Arr, 2, 4>; // expected to be [3, 4]

Back Share your Solutions Check out Solutions

思路

看上去很简单?这真的是 Extreme 难度吗?
难度主要在数字的转换上。TypeScript 不支持直接做类型的加减法,所以需要体操一下获得 Add1<N>MinusXY<X, Y>

type Push1<X extends any[]> = [...X, 1];
type ArrFrom<N, A extends any[] = []> = A["length"] extends N
  ? A
  : ArrFrom<N, Push1<A>>;
type Add1<N> = [...ArrFrom<N>, 1]["length"];
type Minus1<N> = ArrFrom<N> extends [infer _1, ...infer Rest]
  ? Rest["length"]
  : never;
type MinusXY<X, Y> = Y extends 0 ? X : MinusXY<Minus1<X>, Minus1<Y>>;
type Abs<X extends number> = `${X}` extends `-${infer R extends number}`
  ? R
  : X;
type IsNeg<X extends number> = Abs<X> extends X ? false : true;

剩下的就很简单了

type RemoveFirstN<N, Arr extends any[], Removed = 0> = N extends Removed
  ? Arr
  : Arr extends [infer _1, ...infer Rest extends any[]]
  ? RemoveFirstN<N, Rest, Add1<Removed>>
  : [];
type KeepFirstN<
  N,
  Arr extends any[],
  Ret extends any[] = [],
  Kept = 0
> = Kept extends N
  ? Ret
  : Arr extends [infer _1, ...infer Rest extends any[]]
  ? KeepFirstN<N, Rest, [...Ret, _1], Add1<Kept>>
  : [];
type SliceNoNeg<Arr extends any[], From, To> = RemoveFirstN<
  From,
  Arr
> extends infer Res extends any[]
  ? KeepFirstN<To, Res, [], From>
  : never;
type ConvertToPositive<N, X extends number> = IsNeg<X> extends true
  ? MinusXY<N, Abs<X>>
  : X;
type Slice<
  Arr extends any[],
  From extends number = 0,
  To extends number = Arr["length"]
> = SliceNoNeg<
  Arr,
  ConvertToPositive<Arr["length"], From>,
  ConvertToPositive<Arr["length"], To>
>;

所以

这类型体操纯属在折磨自己了吧

Previous  Next

Loading...