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
Arr
to _
.Start
(i.e. _.length === Start
), start moving values to Acc
instead.End
(i.e. _.length + Acc.length === End
), return Acc
Acc
.Start > End
, we can simply check _.length + Acc.length === End
before checking _.length === Start
.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;
}
}
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
: []
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.
// #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