UNPKG

3.35 kBTypeScriptView Raw
1import type {Sum} from './sum';
2import type {LessThanOrEqual} from './less-than-or-equal';
3import type {GreaterThanOrEqual} from './greater-than-or-equal';
4import type {GreaterThan} from './greater-than';
5import type {IsNegative} from './numeric';
6import type {Not, TupleMin} from './internal';
7import type {IsEqual} from './is-equal';
8import type {And} from './and';
9import type {ArraySplice} from './array-splice';
10
11/**
12Returns an array slice of a given range, just like `Array#slice()`.
13
14@example
15```
16import type {ArraySlice} from 'type-fest';
17
18type T0 = ArraySlice<[0, 1, 2, 3, 4]>;
19//=> [0, 1, 2, 3, 4]
20
21type T1 = ArraySlice<[0, 1, 2, 3, 4], 0, -1>;
22//=> [0, 1, 2, 3]
23
24type T2 = ArraySlice<[0, 1, 2, 3, 4], 1, -2>;
25//=> [1, 2]
26
27type T3 = ArraySlice<[0, 1, 2, 3, 4], -2, 4>;
28//=> [3]
29
30type T4 = ArraySlice<[0, 1, 2, 3, 4], -2, -1>;
31//=> [3]
32
33type T5 = ArraySlice<[0, 1, 2, 3, 4], 0, -999>;
34//=> []
35
36function arraySlice<
37 const Array_ extends readonly unknown[],
38 Start extends number = 0,
39 End extends number = Array_['length'],
40>(array: Array_, start?: Start, end?: End) {
41 return array.slice(start, end) as ArraySlice<Array_, Start, End>;
42}
43
44const slice = arraySlice([1, '2', {a: 3}, [4, 5]], 0, -1);
45
46typeof slice;
47//=> [1, '2', { readonly a: 3; }]
48
49slice[2].a;
50//=> 3
51
52// @ts-expect-error -- TS2493: Tuple type '[1, "2", {readonly a: 3}]' of length '3' has no element at index '3'.
53slice[3];
54```
55
56@category Array
57*/
58export type ArraySlice<
59 Array_ extends readonly unknown[],
60 Start extends number = never,
61 End extends number = never,
62> = And<IsEqual<Start, never>, IsEqual<End, never>> extends true
63 ? Array_
64 : number extends Array_['length']
65 ? VariableLengthArraySliceHelper<Array_, Start, End>
66 : ArraySliceHelper<Array_, IsEqual<Start, never> extends true ? 0 : Start, IsEqual<End, never> extends true ? Array_['length'] : End>;
67
68type VariableLengthArraySliceHelper<
69 Array_ extends readonly unknown[],
70 Start extends number,
71 End extends number,
72> = And<Not<IsNegative<Start>>, IsEqual<End, never>> extends true
73 ? ArraySplice<Array_, 0, Start>
74 : And<
75 And<Not<IsNegative<Start>>, Not<IsNegative<End>>>,
76 IsEqual<GreaterThan<End, Start>, true>
77 > extends true
78 ? ArraySliceByPositiveIndex<Array_, Start, End>
79 : [];
80
81type ArraySliceHelper<
82 Array_ extends readonly unknown[],
83 Start extends number = 0,
84 End extends number = Array_['length'],
85 TraversedElement extends Array<Array_[number]> = [],
86 Result extends Array<Array_[number]> = [],
87 ArrayLength extends number = Array_['length'],
88 PositiveS extends number = IsNegative<Start> extends true
89 ? Sum<ArrayLength, Start> extends infer AddResult extends number
90 ? number extends AddResult // (ArrayLength + Start) < 0
91 ? 0
92 : AddResult
93 : never
94 : Start,
95 PositiveE extends number = IsNegative<End> extends true ? Sum<ArrayLength, End> : End,
96> = true extends [IsNegative<PositiveS>, LessThanOrEqual<PositiveE, PositiveS>, GreaterThanOrEqual<PositiveS, ArrayLength>][number]
97 ? []
98 : ArraySliceByPositiveIndex<Array_, TupleMin<[PositiveS, ArrayLength]>, TupleMin<[PositiveE, ArrayLength]>>;
99
100type ArraySliceByPositiveIndex<
101 Array_ extends readonly unknown[],
102 Start extends number,
103 End extends number,
104 Result extends Array<Array_[number]> = [],
105> = Start extends End
106 ? Result
107 : ArraySliceByPositiveIndex<Array_, Sum<Start, 1>, End, [...Result, Array_[Start]]>;