00216-extreme-slice

Back

type ToPositiveIndex<Arr extends any[], Index extends number, Acc extends any[] = []> = `${Index}` extends `-${infer N}`
  ? `${N}` extends `${Acc['length']}`
    ? Arr['length']
    : Arr extends [any, ...infer Rest]
      ? ToPositiveIndex<Rest, Index, [...Acc, any]>
      : never
  : Index

type SlicePositive<Arr, Start, End, Acc extends any[] = []> = End extends Acc['length']
  ? []
  : Arr extends [infer First, ...infer Rest]
    ? Start extends Acc['length']
      ? [First, ...SlicePositive<Rest, [...Acc, any]['length'], End, [...Acc, any]>]
      : SlicePositive<Rest, Start, End, [...Acc, any]>
    : []

type Slice<
  Arr extends any[],
  Start extends number = 0,
  End extends number = Arr['length']
> = SlicePositive<Arr, ToPositiveIndex<Arr, Start>, ToPositiveIndex<Arr, End>>

Solution by 2083335157 #35115

// 绝对值
type Abs<N extends number> = `${N}` extends `-${infer Int extends number}` ? Int : N;

// 下标转换,同时支持正负情形,例如: -1 => length - 1, 1 => 1
type IndexTransform<Arr extends any[], Start extends number, R extends any[] = [any]> = Start extends Abs<Start> 
? Start // 正索引直接返回
: Arr extends [...infer H, infer Tail]
  ? R['length'] extends Abs<Start>
    ? H['length']
    : IndexTransform<H, Start, [...R, any]>
  : 0

// 生成指定长度的元组
type Tuple<T extends number, R extends any[] = []> = R['length'] extends T ? R: Tuple<T, [...R, any]>;

// 比较是否 M < N,用于Slice时,如果 M >= N 直接返回 []
type SmallerThan<M extends number, N extends number> = Tuple<M> extends [...Tuple<N>, ...infer Rest] ? false : true;

// 从 Start 位置到末尾 Slice, 注意:负值需要转换为正数,例如: -1 => length - 1
type SliceFromStart<
  Arr extends any[],
  Start extends number = 0,
  R extends any[] = []
> = R['length'] extends IndexTransform<Arr, Start>
  ? Arr extends [...R, ...infer Rest]
    ? Rest
    : R
  : SliceFromStart<Arr, IndexTransform<Arr, Start>, [...R, any]>;

// 测试用例
type Test13 = SliceFromStart<[1, 2, 3, 4, 5], 0>; // [1, 2, 3, 4, 5]
type Test14 = SliceFromStart<[1, 2, 3, 4, 5], 1>; // [2, 3, 4, 5]
type Test15 = SliceFromStart<[1, 2, 3, 4, 5], 2>; // [3, 4, 5]
type Test16 = SliceFromStart<[1, 2, 3, 4, 5], 3>; // [4, 5]
type Test17 = SliceFromStart<[1, 2, 3, 4, 5], 4>; // [5]
type Test18 = SliceFromStart<[1, 2, 3, 4, 5], 5>; // []
type Test19 = SliceFromStart<[1, 2, 3, 4, 5], -1>; // [5]
type Test20 = SliceFromStart<[1, 2, 3, 4, 5], -2>; // [4, 5]
type Test21 = SliceFromStart<[1, 2, 3, 4, 5], -3>; // [3, 4, 5]
type Test22 = SliceFromStart<[1, 2, 3, 4, 5], -4>; // [2, 3, 4, 5]
type Test23 = SliceFromStart<[1, 2, 3, 4, 5], -5>; // [1, 2, 3, 4, 5]
type Test24 = SliceFromStart<[1, 2, 3, 4, 5], -6>; // [1,2,3,4,5]


// 最终解答,从 Start 位置到 End 位置 Slice,
// 思路:1.比较转换索引后的Start<End,否则直接返回[];2. 分别从Start和End 位置调用SliceFromStart,用前者infer后者,找到不重复的部分即可。
type Slice<
  Arr extends any[],
  Start extends number = 0,
  End extends number = Arr['length'],
  AbsStart extends number = IndexTransform<Arr, Start>,
  AbsEnd extends number = IndexTransform<Arr, End>
> = SmallerThan<AbsStart, AbsEnd> extends true 
? SliceFromStart<Arr, AbsStart> extends [...infer Rest,...SliceFromStart<Arr, AbsEnd>] 
  ? Rest 
  : []
: []

Solution by zheyizhifeng #34860

// e.g.
// NumberToTuple<3> -> [0, 0, 0]
type NumberToTuple<N extends number, Result extends 0[] = []> = Result["length"] extends N
  ? Result
  : NumberToTuple<N, [...Result, 0]>;

// e.g.
// Minus<4, 3> -> 1
type Minus<M extends number, N extends number> = NumberToTuple<M> extends [...NumberToTuple<N>, ...infer Result]
  ? Result["length"]
  : never;

type Slice<
  Arr extends unknown[],
  Start extends number = 0,
  End extends number = Arr["length"],
  Counter extends 0[] = [], // counter (the length represents current index)
  Result extends unknown[] = [] // result list
> =
  // convert negative start index to positive value
  `${Start}` extends `-${infer AbsStart extends number}`
    ? Slice<Arr, Minus<Arr["length"], AbsStart>, End>
    : // convert negative end index to positive value
    `${End}` extends `-${infer AbsEnd extends number}`
    ? Slice<Arr, Start, Minus<Arr["length"], AbsEnd>>
    : //
    Arr extends [infer First, ...infer Rest]
    ? // if reaches end index, return result
      Counter["length"] extends End
      ? Result
      : // if reaches start index, add value to result list.
      Counter["length"] extends Start
      ? Slice<Rest, Start, End, [...Counter, 0], [...Result, First]>
      : //
      Result["length"] extends 0
      ? // if result length is 0, assume that index is before start index
        Slice<Rest, Start, End, [...Counter, 0], Result>
      : // if result length is not 0, assume that index is between start and end index (we should add value to result list)
        Slice<Rest, Start, End, [...Counter, 0], [...Result, First]>
    : Result;

Solution by yukicountry #34531

type Tuple<T, Res extends 1[] = []> = 0 extends 1
  ? never
  : Res["length"] extends T
  ? Res
  : Tuple<T, [...Res, 1]>;
type Subtract<M extends number, S extends number> = Tuple<M> extends [
  ...Tuple<S>,
  ...infer Rest
]
  ? Rest["length"]
  : never;

type StandardizeIndex<
  N extends number,
  L extends number
> = `${N}` extends `-${infer R extends number}` ? Subtract<L, R> : N;

type Slice<
  Arr extends any[],
  Start extends number = 0,
  End extends number = Arr["length"],
  R extends any[] = [],
  C extends 0[] = [],
  StandStart extends number = StandardizeIndex<Start, Arr["length"]>,
  StandEnd extends number = StandardizeIndex<End, Arr["length"]>
> = C["length"] extends StandEnd
  ? R
  : Arr extends [infer F, ...infer L]
  ? C["length"] extends StandStart
    ? Slice<L, StandStart, StandEnd, [F], [...C, 0]>
    : R["length"] extends 0
    ? Slice<L, StandStart, StandEnd, R, [...C, 0]>
    : Slice<L, StandStart, StandEnd, [...R, F], [...C, 0]>
  : [];

Solution by vangie #32343

type To<
	A extends unknown[],
	E extends number,
	R extends unknown[] = [],
> = `${E}` extends `-${infer M extends number}`
	? R["length"] extends M
		? A
		: A extends [...infer F, infer L]
			? To<F, E, [L, ...R]>
			: A
	: R["length"] extends E
		? R
		: A extends [infer F, ...infer L]
			? To<L, E, [...R, F]>
			: R;

type Slice<A extends unknown[], S extends number = 0, E extends number = A["length"]> = To<
	A,
	E
> extends [...To<A, S>, ...infer R]
	? R
	: [];

Solution by alexandroppolus #32287

type IndexAbs<
    Arr extends Array<unknown>,
    T extends number
> = `${T}` extends `-${infer N extends number}` ? Slice<Arr, N>['length'] : T

type Slice<
    Arr extends Array<unknown>,
    Start extends number = 0,
    End extends number = Arr['length'],
    _ extends Array<unknown> = [],
    Acc extends Array<unknown> = [],
    Original extends Array<unknown> = [..._, ...Acc, ...Arr]
> = Arr extends [infer First, ...infer Rest]
    ? [..._, ...Acc]['length'] extends IndexAbs<Original, End>
        ? Acc
        : _['length'] extends IndexAbs<Original, Start>
        ? Slice<Rest, Start, End, _, [...Acc, First]>
        : Slice<Rest, Start, End, [..._, First], Acc>
    : Acc

TS Playground

Approach

  1. Start by moving values from Arr to _.
  2. Once we reach Start (i.e. _.length === Start), start moving values to Acc instead.
  3. When we reach End (i.e. _.length + Acc.length === End), return Acc

Dealing with negative index

  1. Slice the array with absolute value of the index
  2. Get the length of the sliced array and use it as the new index

Dealing with invalid input

Solution by satohshi #31355

// this bit is inspired by https://github.com/type-challenges/type-challenges/issues/22110
type ToPositive<N extends number, Arr extends unknown[]> =
  `${N}` extends `-${infer P extends number}`
  ? Slice<Arr, P>['length']
  : N;

type Slice<Arr extends unknown[], Start extends number = 0,
  End extends number = Arr['length'],
  Count extends unknown[] = [], Res extends unknown[] = [],
  Extract extends boolean = false> =
  Arr extends [infer Head, ...infer Tail] ?
      ToPositive<End, Arr> extends Count['length'] ?
        Res :
    Extract extends true ?
          Slice<Tail, ToPositive<Start, Arr>, ToPositive<End, Arr>, [...Count, 1], [...Res, Head], true> :
        Start extends Count['length'] ?
          Slice<Tail, Start, ToPositive<End, Arr>, [...Count, 1], [...Res, Head], true> :
          Slice<Tail, ToPositive<Start, Arr>, ToPositive<End, Arr>, [...Count, 1], Res, Extract>:
        Res;

Solution by dioxmio #31255

// 解答をここに記入


// 与えられた長さをもつ never[] を返す
type CreateArr<N, Ans extends never[] = []> = Ans["length"] extends N ? Ans : CreateArr<N, [never, ...Ans]>

// index と Arr を受け取り、非負ならそのままで、負の数なら Length の後ろから分で該当する index を返す
type GetIndex<Index extends number, Arr extends unknown[]> = `${Index}` extends `-${infer P extends number}` ? CreateArr<Arr["length"]> extends [...CreateArr<P>, ...infer Rest] ? Rest["length"] : never : Index

// Start, End が適切な大小関係かを返す (Start <= End であるべき)
type IsStartEndValid<Start, End, Counter extends never[] = []> = Counter["length"] extends Start ? true : Counter["length"] extends End ? false : IsStartEndValid<Start, End, [never, ...Counter]>

// Flag を切り替えるべきタイミングでは切り替え先を、そうでない場合は never を返す
type GetFlag<Start, End, Counter> = End extends Counter ? false : Start extends Counter ? true : never

// Slice を行う
type InnerSlice<Arr extends unknown[], Start, End, Counter extends never[] = [], Flag = false> = 
  Arr extends [infer F, ...infer Rest]
  ? GetFlag<Start, End, Counter["length"]> extends never ? [...(Flag extends true ? [F] : []), ...InnerSlice<Rest, Start, End, [never, ...Counter], Flag>]
  : GetFlag<Start, End, Counter["length"]> extends true ? [F, ...InnerSlice<Rest, Start, End, [never, ...Counter], true>] : InnerSlice<Rest, Start, End, [never, ...Counter], false>
  : []

// Start, End をバリデーションしてから、よければ InnerSlice を実行する
type Slice<Arr extends unknown[], Start extends number = 0, End extends number = Arr["length"], S = GetIndex<Start, Arr>, G = GetIndex<End, Arr>> = [S, G] extends [number, number] ? IsStartEndValid<S, G> extends true ? InnerSlice<Arr, S, G> : [] : []

Solution by Kakeru-Miyazaki #30984

Though contain many helper method, but it is very straightforward. All test case passed.


type NumberToArray<T extends number, S extends unknown[] = []> = S['length'] extends T ? S : NumberToArray<T, [...S, 1]>

//  A.len > B.len
type _MinusAB<A extends any[], B extends any[], R extends any[] = []> = 
    A["length"] extends B["length"] ? R["length"] : _MinusAB<A, [1, ...B], [1, ...R]>

// return converted/normalized/positive index pos:
type NormalizeIndex<A extends any[], N extends number, Ng=`${N}`> = Ng extends `-${infer E extends number}` 
    ? _MinusAB<A, NumberToArray<E>> 
    : N

type getHead<A, N, R extends any[] = []> = A extends [infer F, ... infer Tail] 
  ? R['length'] extends N ? R : getHead<Tail, N, [ ...R, F]> 
  : R

type getTail<A extends any[], N, Pop extends any[] = [], Tail extends any[] = A> = Pop['length'] extends N  
  ? Tail 
  : A extends [infer F, ... infer Tail] 
    ? getTail<Tail, N, [... Pop, F], Tail>
    : []

type Slice<Arr extends any[], Start extends number=0, End extends number= Arr["length"]> 
  = getTail<getHead<Arr, NormalizeIndex<Arr, End>>, NormalizeIndex<Arr, Start>>


Solution by code-brewer #30258

type TupleOfLength<N, T extends any[] = []> = T['length'] extends N
	? T[number]
	: TupleOfLength<N, [...T, T['length']]>;

type NumberRange<L, H> = Exclude<TupleOfLength<H>, TupleOfLength<L>>;

type Get<T extends any[], O extends number, J extends any[] = []> = T extends [
	infer E,
	...infer R
]
	? J['length'] extends O
		? [E, ...Get<R, O, [0, ...J]>]
		: Get<R, O, [0, ...J]>
	: [];

type GetArr<T extends number, O extends number[] = []> = O['length'] extends T
	? O
	: GetArr<T, [0, ...O]>;

type Calc<
	A extends number[],
	B extends string,
	H extends number[] = []
> = `${H['length']}` extends B
	? A['length']
	: A extends [infer E extends number, ...infer R extends number[]]
	? Calc<R, B, [E, ...H]>
	: 0;

type Slice<
	T extends any[],
	S extends number = 0,
	E extends number = T['length']
> = `${S}` extends `-${infer SR}`
	? `${E}` extends `-${infer ER}`
		? Get<
				T,
				NumberRange<
					Calc<GetArr<T['length']>, SR>,
					Calc<GetArr<T['length']>, ER>
				>
		  >
		: Get<T, NumberRange<Calc<GetArr<T['length']>, SR>, E>>
	: `${E}` extends `-${infer ER}`
	? Get<T, NumberRange<S, Calc<GetArr<T['length']>, ER>>>
	: Get<T, NumberRange<S, E>>;

Solution by Royce-DaDaDa #29832

type NumberToTuple<N extends number, T extends unknown[] = []> = T['length'] extends N
  ? T
  : NumberToTuple<N, [...T, unknown]>;

type Slice<
  Arr extends unknown[],
  Start extends number = 0,
  End extends number = Arr['length'],
> = Arr extends [
  ...NumberToTuple<Slice.ParseStartIndex<Arr, Start> | Arr['length']>,
  ...infer Result,
  ...NumberToTuple<Slice.ParseEndIndex<Arr, End> | Arr['length']>,
]
  ? Result
  : [];

namespace Slice {
  export type ParseStartIndex<
    Arr extends unknown[],
    I extends number,
  > = `${I}` extends `-${infer INegative extends number}` ? ParseIndex.RevertIndex<Arr, INegative> : I;
  export type ParseEndIndex<
    Arr extends unknown[],
    I extends number,
  > = `${I}` extends `-${infer INegative extends number}` ? INegative : ParseIndex.RevertIndex<Arr, I>;
  namespace ParseIndex {
    export type RevertIndex<Arr extends unknown[], INegative extends number> = Arr extends [
      ...NumberToTuple<INegative>,
      ...infer IRevertedTuple,
    ]
      ? IRevertedTuple['length']
      : never;
  }
}

Playground

Solution by BOCbMOU #27714

type NTuple<N extends number, Arr extends any[] = []> = Arr extends {
  length: N;
}
  ? Arr
  : NTuple<N, [...Arr, any]>;

type Sub<N1 extends number, N2 extends number> = NTuple<N1> extends [
  ...infer R,
  ...NTuple<N2>
]
  ? R["length"]
  : never;

type Slice<
  T extends any[],
  S extends number,
  E extends number,
  Idx extends any[] = NTuple<S>
> = Sub<E, Idx["length"]> extends 0
  ? []
  : [T[Idx["length"]], ...Slice<T, S, E, [...Idx, any]>];

Solution by slemchik03 #27661

type NumberToTuple<T extends number, U extends 1[] = []> = U['length'] extends T
  ? U
  : NumberToTuple<T, [...U, 1]>;

type Subtract<A extends number, B extends number> = NumberToTuple<A> extends [
  ...NumberToTuple<B>,
  ...infer R
]
  ? R['length']
  : 0;

type ToNonNegativeIndex<
  Index extends number,
  Length extends number
> = `${Index}` extends `-${infer AbsIndex extends number}`
  ? Subtract<Length, AbsIndex>
  : Index;

type SliceWithNonNegativeIndices<
  Arr,
  Start,
  End,
  Index extends 1[] = [],
  Result extends unknown[] = []
> = End extends Index['length']
  ? Result
  : Arr extends [infer F, ...infer R]
  ? Start extends Index['length'] | 0
    ? SliceWithNonNegativeIndices<R, 0, End, [...Index, 1], [...Result, F]>
    : SliceWithNonNegativeIndices<R, Start, End, [...Index, 1], Result>
  : [];

type Slice<
  Arr extends unknown[],
  Start extends number = 0,
  End extends number = Arr['length']
> = SliceWithNonNegativeIndices<
  Arr,
  ToNonNegativeIndex<Start, Arr['length']>,
  ToNonNegativeIndex<End, Arr['length']>
>;

Solution by JohnLi1999 #26830

/**造数组 */
type MakeArray<T extends number, E = never, _Result extends any[] = []> = _Result[`length`] extends (T | 999) ? _Result : MakeArray<T, E, [..._Result, _Result[`length`]]>;
/**比较大于 */
type SimpleGreaterThan<T1 extends number, T2 extends number, _Counter extends any[] = []> = T1 extends T2 ? false : _Counter[`length`] extends T1 ? false : _Counter[`length`] extends T2 ? true : SimpleGreaterThan<T1, T2, [..._Counter, never]>;
/**有效索引集 */
type ValidIndexes<T extends any[]> = keyof { [P in keyof T as P extends `${infer N extends number}` ? N : never]: P } | T[`length`];
/**正索引 */
type IndexFix<T extends any[], I extends number, _Counter extends any[] = []> = `${I}` extends `-${infer N extends number}`/*<0*/ ? _Counter[`length`] extends N ? T[`length`] : (T extends [...infer R, any] ? IndexFix<R, I, [..._Counter, 1]> : _Counter[`length`])/*length-*/ : I;

/**截取后半段 */
type SliceStart<Arr extends any[], Start extends number = 0, _Counter extends any[] = []> = Arr extends [infer F, ...infer R] ? (_Counter[`length`] extends Start ? Arr : SliceStart<R, Start, [..._Counter, F]>) : [];
type Slice<Arr extends any[], Start extends number = 0, End extends number = Arr[`length`],
  _Result extends any[] = MakeArray<IndexFix<Arr, Start>>,
  _Start extends number = IndexFix<Arr, Start>,
  _End extends number = IndexFix<Arr, End>> =
  [1] extends [((_Start extends ValidIndexes<Arr> ? 1 : 2) & (_End extends ValidIndexes<Arr> ? 1 : 2)) & (SimpleGreaterThan<_End, _Start> extends true ? 1 : 2)] ?  //Start合法 && End合法 && End>Start
  (_Result[`length`] extends _End ?
    SliceStart<_Result, _Start> :   //return
    Slice<Arr, _Start, _End, [..._Result, Arr[_Result[`length`]]]>) :
  [];   //invalid

Solution by E-uler #25436

/**造数组 */
type MakeArray<T extends number, E = never, _Result extends any[] = []> = _Result[`length`] extends (T | 999) ? _Result : MakeArray<T, E, [..._Result, _Result[`length`]]>;
/**比较大于 */
type SimpleGreaterThan<T1 extends number, T2 extends number, _Counter extends any[] = []> = T1 extends T2 ? false : _Counter[`length`] extends T1 ? false : _Counter[`length`] extends T2 ? true : SimpleGreaterThan<T1, T2, [..._Counter, never]>;
/**有效索引集 */
type ValidIndexes<T extends any[]> = keyof { [P in keyof T as P extends `${infer N extends number}` ? N : never]: P } | T[`length`];
/**正索引 */
type IndexFix<T extends any[], I extends number, _Counter extends any[] = []> = `${I}` extends `-${infer N extends number}`/*<0*/ ? _Counter[`length`] extends N ? T[`length`] : (T extends [...infer R, any] ? IndexFix<R, I, [..._Counter, 1]> : _Counter[`length`])/*length-*/ : I;

/**截取后半段 */
type SliceStart<Arr extends any[], Start extends number = 0, _Counter extends any[] = []> = Arr extends [infer F, ...infer R] ? (_Counter[`length`] extends Start ? Arr : SliceStart<R, Start, [..._Counter, F]>) : [];
type Slice<Arr extends any[], Start extends number = 0, End extends number = Arr[`length`],
  _Result extends any[] = MakeArray<IndexFix<Arr, Start>>,
  _Start extends number = IndexFix<Arr, Start>,
  _End extends number = IndexFix<Arr, End>> =
  [1] extends [((_Start extends ValidIndexes<Arr> ? 1 : 2) & (_End extends ValidIndexes<Arr> ? 1 : 2)) & (SimpleGreaterThan<_End, _Start> extends true ? 1 : 2)] ?  //Start合法 && End合法 && End>Start
  (_Result[`length`] extends _End ?
    SliceStart<_Result, _Start> :   //return
    Slice<Arr, _Start, _End, [..._Result, Arr[_Result[`length`]]]>) :
  [];   //invalid

Solution by E-uler #25435

type NumberToArr<T extends number, R extends unknown[] = []> =
  R['length'] extends T
    ? R
    : NumberToArr<T, [...R, 0]>

type ToPositiveIndex<
  Arr extends unknown[],
  N extends number,
> =
  `${N}` extends `-${infer P extends number}`
    ? NumberToArr<Arr['length']> extends [...NumberToArr<P>, ...infer Rest]
      ? Rest['length']
      : 0
    : N

type Slice<
  Arr extends unknown[],
  Start extends number = 0,
  End extends number = Arr['length'],
  Index extends unknown[] = [],
  R extends unknown[] = [],
  PStart extends number = ToPositiveIndex<Arr, Start>,
  PEnd extends number = ToPositiveIndex<Arr, End>,
> =
  Arr extends [infer A, ...infer Rest]
    ? Index['length'] extends PEnd
      ? R
      : Index['length'] extends PStart
        ? Slice<Rest, PStart, PEnd, [...Index, 0], [...R, A]>
        : R['length'] extends 0
          ? Slice<Rest, PStart, PEnd, [...Index, 0], R>
          : Slice<Rest, PStart, PEnd, [...Index, 0], [...R, A]>
    : R

Solution by drylint #23315

// your answers
type GreaterThan<
    D1 extends number,
    D2 extends number,
    hasEqual extends boolean = false,
    A extends unknown[] = []
  > = D1 extends D2
    ? hasEqual
    : A["length"] extends D1
    ? false
    : A["length"] extends D2
    ? true
    : GreaterThan<D1, D2, hasEqual, [unknown, ...A]>;

 
  // 判断是否是负数
  type IsNegative<T extends number> = `${T}` extends `-${number}`
    ? true
    : false;
  type NegativeToPositive<T extends number> =
    `${T}` extends `-${infer R extends number}` ? R : never;

  type NegativeModArrIndex<
    T extends number,
    Arr extends any[],
    I extends 0[] = []
  > = IsNegative<T> extends true
    ? Arr extends [any, ...infer R]
      ? [0, ...I]["length"] extends NegativeToPositive<T>
        ? R["length"]
        : NegativeModArrIndex<T, R, [0, ...I]>
      : Arr["length"]
    : T;

  type PositiveSlice<
    T extends any[],
    Start extends number,
    End extends number,
    I extends 0[] = [],
    CrossStart extends boolean = Start extends 0 ? true : false
  > = T extends [infer F, ...infer R]
    ? CrossStart extends true
      ? I["length"] extends End
        ? []
        : [F, ...PositiveSlice<R, Start, End, [0, ...I], CrossStart>]
      : I["length"] extends Start
      ? [F, ...PositiveSlice<R, Start, End, [0, ...I], true>]
      : PositiveSlice<R, Start, End, [0, ...I], CrossStart>
    : [];

 type Slice<
    T extends any[],
    Start extends number = 0,
    End extends number = T["length"]
  > = GreaterThan<
    NegativeModArrIndex<Start, T>,
    NegativeModArrIndex<End, T>,
    true
  > extends true
    ? []
    : PositiveSlice<
        T,
        NegativeModArrIndex<Start, T>,
        NegativeModArrIndex<End, T>
      >;

Solution by acwink #22174

// if N is negative, convert it to its positive counterpart by the Arr
type ToPositive<N extends number, Arr extends unknown[]> =
  `${N}` extends `-${infer P extends number}`
  ? Slice<Arr, P>['length']
  : N

// get the initial N items of Arr
type InitialN<Arr extends unknown[], N extends number, _Acc extends unknown[] = []> = 
  _Acc['length'] extends N | Arr['length']
  ? _Acc
  : InitialN<Arr, N, [..._Acc, Arr[_Acc['length']]]>

type Slice<Arr extends unknown[], Start extends number = 0, End extends number = Arr['length']> = 
  InitialN<Arr, ToPositive<End, Arr>> extends [...InitialN<Arr, ToPositive<Start, Arr>>, ...infer Rest]
  ? Rest
  : []

playground

Solution by zhaoyao91 #22110

// your answers

type SubString<
    A extends any[], // Arr
    S extends number, // Start
    E extends number, // End
    R extends any[] = [],
    C extends any[] = [] // Count
> =
    A extends [infer F, ... infer L extends any[]]
    ? (C['length'] extends E
        ? R
        : S extends 0 | C['length']
        ? SubString<L, 0, E, [...R, F], [...C, unknown]>
        : SubString<L, S, E, R, [...C, unknown]>
    )
    : R
// -1 >>> Length -1 
type Emmmm<A extends any[], N extends number, T extends any[] = []>
    = A extends [infer AA, ...infer BB]
    ? N extends T['length'] ? A['length'] : Emmmm<BB, N, [...T, unknown]>
    : A['length']

type Slice<
    Arr extends any[],
    Start extends number = 0,
    End extends number = Arr['length'],
> =
    `${Start}` extends `-${infer N extends number}`
    ? Slice<Arr, Emmmm<Arr, N>, End>
    : `${End}` extends `-${infer N extends number}`
    ? Slice<Arr, Start, Emmmm<Arr, N>>
    : SubString<Arr, Start, End>

Solution by goddnsgit #22109

type Subtraction<
  A extends number,
  B extends number,
  AArray extends unknown[] = LengthToArray<A>,
  BArray extends unknown[] = [],
> = BArray['length'] extends B
  ? AArray['length']
  : AArray extends [infer F, ...infer R]
    ? Subtraction<A, B, R, [...BArray, F]>
    : 'A must greater than B'

type SliceWithPositiveNumber<
  Arr extends number[],
  Start = 0,
  End = Arr['length'],
  Left extends unknown[] = [],
  T extends unknown[] = [],
> = Arr extends [infer F, ...infer R extends number[]]
  ? Start extends number
    ? GreaterThan<Start, Left['length']> extends true
      ? SliceWithPositiveNumber<R, Start, End, [...Left, F]>
      : End extends number
        ? GreaterThan<End, Left['length']> extends true
          ? SliceWithPositiveNumber<R, Start, End, [...Left, F], [...T, F]>
          : T
        : never
    : never
  : T

  type Slice<
    Arr extends number[],
    Start extends number = 0,
    End extends number = Arr['length'],
    Length extends number = Arr['length'],
  > = SliceWithPositiveNumber<
    Arr,
    `${Start}` extends `-${infer S extends number}`
      ? Subtraction<Length, S>
      : Start,
    `${End}` extends `-${infer E extends number}`
      ? Subtraction<Length, E>
      : End
  >

Solution by thanhhtse04588 #22018

It's so extreme level as so much time I had spent to solute it.

Playground.

// #4425
type _GreaterThan<T extends number, U extends number, Arr extends 0[] = []> =
  U extends Arr['length']
    ? T extends Arr['length']
      ? false // 相等
      : true // T 数字更大
    : T extends Arr['length']
      ? false // 先到达 T,证明 U 数字更大
      : _GreaterThan<T, U, [ ...Arr, 0 ]> // 两个都没到达

type _ToPositiveIdx<N extends number, Arr extends unknown[], _Counter extends 0[] = []> =
  `${ N }` extends `-${ infer I extends number }`
    ? _Counter['length'] extends I
      ? Arr['length']
      : Arr extends [ unknown, ...infer Rest ]
        ? _ToPositiveIdx<N, Rest, [ ..._Counter, 0 ]>
        : never
    : N

type _VerifyIdx<A extends number, B extends number, Max extends number> =
  _GreaterThan<A, B> extends true
    ? false
    : _GreaterThan<A, Max> extends true
      ? false
      : _GreaterThan<B, Max> extends true
        ? false
        : true


type Slice<
  Arr extends unknown[],
  Start extends number = 0,
  End extends number = Arr['length'],
  _Idx extends 0[] = [],
  _OverStart extends boolean = false,
  _Result extends unknown[] = [],
  _Start extends number = _ToPositiveIdx<Start, Arr>,
  _End extends number = _ToPositiveIdx<End, Arr>,
  _CurrentValue extends Arr[number] = Arr[_Idx['length']],
  _ValidIdx extends boolean = _VerifyIdx<_Start, _End, Arr['length']>,
> = _ValidIdx extends false
  ? []
  : _Idx['length'] extends _Start
    ? _Idx['length'] extends _End
      ? []
      : Slice<Arr, _Start, _End, [ ..._Idx, 0 ], true, [ _CurrentValue ]>
    : _OverStart extends false
      ? Slice<Arr, _Start, _End, [ ..._Idx, 0 ], false>
      : _Idx['length'] extends _End
        ? _Result
        : Slice<Arr, _Start, _End, [ ..._Idx, 0 ], true, [ ..._Result, _CurrentValue ]>

Solution by lvjiaxuan #21878

/** 
 * @typedef Slice
 * @params START_POS?, END_POS? - START, END converted to positive indices
 * @returns T.slice(START_POS, END_POS)
 */
type Slice<
  T extends unknown[], 
  START extends number = 0, 
  END extends number = T["length"],
  START_POS extends number = IsNonNegative<START> extends true 
    ? START
    : Subtract<T["length"], Absolute<START>>,
  END_POS extends number = IsNonNegative<END> extends true 
    ? Subtract<T["length"], END>
    : Absolute<END>,
  RESULT = OutOfBounds<START_POS, END_POS, [0, T["length"]]> extends true 
    ? [] 
    : Shift<Pop<T, END_POS>, START_POS>,
  > = RESULT;
/** @returns true if I, J are not numbers or [I, J) is unbounded by [RANGE[0], RANGE[1]) */
type OutOfBounds<LO extends number | never, HI extends number | never, RANGE extends number[]> = 
  LO extends never ? true : HI extends never ? true
    : LessThan<LO, RANGE[0]> extends true ? true 
    : LessThan<RANGE[1], HI> extends true ? true : false;
type IntADT = number | string | bigint;

type Signum<N extends IntADT> = 
  `${N}` extends '0' ? 0
    : `${N}` extends `-${infer _}` ? -1 : 1;

type IsNegative<N extends IntADT> = 
  Signum<N> extends -1 ? true : false;

type IsNonNegative<N extends IntADT> = 
  IsNegative<N> extends false ? true : false;

type Absolute<N extends number> = 
  `${N}` extends `-${infer R extends number}` ? R : N;

type Shift<T extends any[], N extends number = 1> = 
  N extends 0 ? T 
    : T extends [infer _, ...infer Rest]
      ? Shift<Rest, Subtract<N, 1>>
      : [];
      
type Pop<T extends any[], N extends number = 1> = 
  N extends 0
    ? T
    : T extends [...infer Rest, infer _]
      ? Pop<Rest, Subtract<N, 1>>
      : [];

type Subtract<M extends number, S extends number> = 
  Repeat<M> extends [...Repeat<S>, ...infer Rest] ? Rest["length"] : never;

type Repeat<N extends number, T extends unknown = null, M extends T[] = []> = 
  M["length"] extends N ? M : Repeat<N, T, [...M, T]>;

type LessThan<T extends number, U extends number> = 
  Equal<T, U> extends true ? false
    : Subtract<T, U> extends never ? true : false;

Solution by MajorLift #21502


type Build<
  T extends number,
  Result extends Array<never> = []
> = Result["length"] extends T ? Result : Build<T, [...Result, never]>;

type EGT<T extends number, B extends number> = Build<T> extends [
  ...Build<B>,
  ...infer C
]
  ? true
  : false;

  type Div<A extends number, B extends number> = Build<A> extends [
  ...Build<B>,
  ...infer C
]
  ? C["length"]
  : Build<B> extends [...Build<A>, ...infer C]
  ? `-${C["length"]}` extends `${infer G extends number}`
    ? G
    : never
  : never;

type Slice_2<
  T extends unknown[],
  Count extends number = 0,
  Result extends Array<any> = []
> = Result["length"] extends Count
  ? T extends [...Result, ...infer Other]
    ? Other
    : []
  : Slice_2<T, Count, [unknown, ...Result]>;

type Slice_1<
  T extends unknown[],
  Count extends number = 0,
  Result extends Array<any> = []
> = Result["length"] extends Count
  ? Result
  : T extends [infer A, ...infer B]
  ? Slice_1<B, Count, [...Result, A]>
  : [];

type NomadizeNumber<
  T extends number,
  Length extends number
> = `${T}` extends `-${infer C extends number}` ? Div<Length, C> : T;

type Slice<
  Arr extends Array<any>,
  Start extends number = 0,
  End extends number = Arr["length"],
  Start_ extends number = NomadizeNumber<Start, Arr["length"]>,
  End_ extends number = NomadizeNumber<End, Arr["length"]>
> = [true] extends [EGT<Start_, End_> | EGT<Start_, Arr["length"]>]
  ? []
 : Slice_1<Slice_2<Arr, Start_>, Div<End_, Start_>>;




Solution by so11y #21392

type SliceLeft<Arr extends readonly any[], Start, isNegStart, PrevArr extends readonly any[] = []> = 
  (isNegStart extends true ? Arr['length'] : PrevArr['length']) extends Start ? Arr
  : Arr extends [infer TFirst, ...infer TRest] ? SliceLeft<TRest, Start, isNegStart, [...PrevArr, TFirst]>
  : [];
type SliceLeftIgnoreSign<Arr extends readonly any[], Start extends number> = 
  `${Start}` extends `-${infer PosStart extends number}` ? SliceLeft<Arr, PosStart, true> : SliceLeft<Arr, Start, false>;


type SliceRight<Arr extends readonly any[], End extends number, isNegEnd, PrevArr extends readonly any[] = []> = 
  (isNegEnd extends true ? PrevArr['length'] : Arr['length']) extends End ? Arr
  : Arr extends [...infer TRest, infer TLast] ? SliceRight<TRest, End, isNegEnd, [TLast, ...PrevArr]>
  : [];
type SliceRightIgnoreSign<Arr extends readonly any[], End extends number> = 
  `${End}` extends `-${infer PosEnd extends number}` ? SliceRight<Arr, PosEnd, true> : SliceRight<Arr, End, false>;


type Slice<Arr extends readonly any[], Start extends number = 0, End extends number = Arr['length']> = 
  `${Start}` extends `-${string}` ? SliceRightIgnoreSign<SliceLeftIgnoreSign<Arr, Start>, End>
  : SliceLeftIgnoreSign<SliceRightIgnoreSign<Arr, End>, Start>

Solution by mdakram28 #20648

type IsNegative<N extends number> = `${N}` extends `-${infer R}` ? true : false

type Shift<Arr extends any[], S extends number, Count extends any[] = []> = Arr extends [infer Head, ...infer Tail] 
  ? Count['length'] extends S
    ? Arr : Shift<Tail, S, [...Count, 1]>
  : Arr

type Pop<Arr extends any[], P extends number, Count extends any[] = []> = Arr extends [...infer Head, infer Tail] 
  ? Arr['length'] extends P
    ? Arr : Pop<Head, P, [...Count, 1]>
  : Arr

type NegToPos<
  N extends number,
  Arr extends any[],
  PosNum extends number = `${N}` extends `-${infer T extends number}` ? T : N,
> = Shift<Arr, PosNum> extends [...infer T] ? T['length'] : 0

type Slice<Arr extends any[], Start extends number = 0, End extends number = Arr['length']> = 
  Pop<Arr, IsNegative<End> extends true ? NegToPos<End, Arr> : End> extends [...infer F]
    ? Shift<F, IsNegative<Start> extends true ? NegToPos<Start, Arr> : Start> extends [...infer R] ? R : [] : []

Solution by Zhukov87 #19993

type NormalizeIndex<
  T extends unknown[],
  I extends number,
  P extends unknown[] = []
> = `${I}` extends `-${infer N}`
  ? `${P['length']}` extends N
    ? T['length']
    : T extends [...infer A, infer B]
    ? NormalizeIndex<A, I, [...P, B]>
    : T['length']
  : I

type Slice<
  Arr extends unknown[],
  Start extends number = 0,
  End extends number = Arr['length'],
  NStart extends number = NormalizeIndex<Arr, Start>,
  NEnd extends number = NormalizeIndex<Arr, End>,
  I extends unknown[] = []
> = I['length'] extends NEnd | Arr['length']
  ? []
  : I['length'] extends NStart
  ? [...I, unknown]['length'] extends number
    ? [
        Arr[I['length']],
        ...Slice<
          Arr,
          Start,
          End,
          [...I, unknown]['length'],
          NEnd,
          [...I, unknown]
        >
      ]
    : never
  : Slice<Arr, Start, End, NStart, NEnd, [...I, unknown]>

Solution by theoolee #19841

// remove the tail starting with End (non-negative)
// Head is the substring starting from Arr[0]
// Tail is the rest of it
// therefore cut when Head['length'] is End
// notice the Head/Tail here are not the same as the Head/Tail in my caller (Slice3<>).
type Cut<
  Arr extends number[], End extends number, 
  Head extends number[], Tail extends number[], R extends number[] = []
> = End extends Head['length']
  ? R
  : Tail extends [infer A1 extends number, ...infer T extends number[]]
    ? Cut<Arr, End, [...Head, A1], T, [...R, A1]>
    : []
;

// Start and End are non-negative
// find the substring starting at Start and pass to Cut<> to remove tail
// Head is a substring starting from Arr[0], growing from []
// Tail is the rest of Arr[], starting with the whole array
// The final result is a left$() of Tail
type Slice3<
  Arr extends number[], Start extends number = 0, End extends number = Arr['length'], 
  Head extends number[] = [], Tail extends number[] = Arr
> = Start extends Head['length']
  ? Cut<Arr, End, Head, Tail>
  : Tail extends [infer A1 extends number, ...infer T extends number[]]
    ? Slice3<Arr, Start, End, [...Head, A1], T>
    : [];

// convert negative length to positive equivalent
// Input: Length > 0 (negative sign already removed)
// Output: Arr['length'] - Length
type N2P<Arr extends number[], Length extends number, R extends number[] = [], L extends unknown[] = []> = Arr extends [...infer T extends number[], infer A9 extends number]
  ? Length extends R['length']
    ? Arr['length']
    : N2P<T, Length, [A9, ...R]>
  : L['length'];

// handle negative indexes to always return a non-negative index
// leave positive indexes untouched
type UnNeg<Arr extends number[], Length extends number> = `${Length}` extends `-${infer S extends number}`
  ? N2P<Arr, S>
  : Length;

type Slice<
  Arr extends number[], Start extends number = 0, End extends number = Arr['length'], 
  Head extends number[] = [], Tail extends number[] = Arr
> = Slice3<Arr, UnNeg<Arr, Start>, UnNeg<Arr, End>, Head, Tail>// your answers

Solution by alexfung888 #18720

type SliceFrom<A extends unknown[], N extends number, R extends unknown[] = []> = A extends [infer F, ...infer O]
  ? R['length'] extends N
    ? A
    : SliceFrom<O, N, [...R, F]>
  : []
type SliceTo<A extends unknown[], N extends number, R extends unknown[] = []> = A extends [infer F, ...infer O]
  ? R['length'] extends N
    ? R
    : SliceTo<O, N, [...R, F]>
  : R
type Slice<A extends any[], F extends number, T extends number> = SliceFrom<SliceTo<A, T>, F>

Solution by shixia226 #18145

type SmallerThan<T extends number, U extends number, R extends any[] = []> = U extends R['length'] ? false : T extends R['length'] ? true : SmallerThan<T, U, [...R, 1]>; // 获得自然数索引 type _GetPlusIndex<T extends string, R extends any[], Q extends 0[] = []> = T extends ${Q['length']} ? R['length'] : R extends [...infer S, infer U] ? _GetPlusIndex<T, S, [...Q, 0]> : 0; type GetPlusIndex<T extends number | string, R extends any[]> = ${T} extends -${infer F} ? _GetPlusIndex<F, R> : T; // 加工 type _SliceEnd<T extends any[], End extends number> = SmallerThan<End, T['length']> extends true ? T extends [...infer R, infer S] ? _SliceEnd<R, End> : T : T; type _SliceStart<T extends any[], Start extends number, Q extends any[] = []> = T['length'] extends Start ? Q : T extends [...infer R, infer S] ? _SliceStart<R, Start, [S, ...Q]> : Q; type _Slice<T extends any[], Start extends number, End extends number> = _SliceStart<_SliceEnd<T, End>, Start>; type Slice<T extends number[], Start extends number, End extends number, S extends number = GetPlusIndex<Start, T>, E extends number = GetPlusIndex<End, T>> = SmallerThan<S, E> extends true ? _Slice<T, S, E> : [];

Solution by my5201314zwl #17286

type Minus<T extends any[], N extends number, C extends any[] = []> =
  C['length'] extends N
    ? T['length']
    : T extends [any, ...infer R]
      ? Minus<R, N, [...C, any]>
      : 0;
type GreaterThan<L extends number, R extends number, C extends any[] = []> =
  C['length'] extends L
    ? false
    : C['length'] extends R
      ? true
      : GreaterThan<L, R, [...C, any]>;
type SliceNormal<Arr extends any[], Start = 0, End = Arr['length'], Count extends any[] = [], Started = Count['length'] extends Start ? true : false> =
  Started extends true
    ? Count['length'] extends End
      ? []
      : Arr extends [infer F, ...infer R]
        ? [F, ...SliceNormal<R, Start, End, [...Count, any], true>]
        : []
    : Arr extends [any, ...infer R]
      ? SliceNormal<R, Start, End, [...Count, any]>
      : [];
type Slice<Arr extends any[], Start extends number = 0, End extends number = Arr['length']> =
  `${Start}` extends `-${infer S extends number}`
    ? Slice<Arr, Minus<Arr, S>, End>
    : `${End}` extends `-${infer E extends number}`
      ? Slice<Arr, Start, Minus<Arr, E>>
      : GreaterThan<End, Start> extends true
        ? SliceNormal<Arr, Start, End>
        : [];

Solution by BulatDashiev #16980