UNPKG

3.43 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> = Array_ extends unknown // To distributive type
63 ? And<IsEqual<Start, never>, IsEqual<End, never>> extends true
64 ? Array_
65 : number extends Array_['length']
66 ? VariableLengthArraySliceHelper<Array_, Start, End>
67 : ArraySliceHelper<Array_, IsEqual<Start, never> extends true ? 0 : Start, IsEqual<End, never> extends true ? Array_['length'] : End>
68 : never; // Never happens
69
70type VariableLengthArraySliceHelper<
71 Array_ extends readonly unknown[],
72 Start extends number,
73 End extends number,
74> = And<Not<IsNegative<Start>>, IsEqual<End, never>> extends true
75 ? ArraySplice<Array_, 0, Start>
76 : And<
77 And<Not<IsNegative<Start>>, Not<IsNegative<End>>>,
78 IsEqual<GreaterThan<End, Start>, true>
79 > extends true
80 ? ArraySliceByPositiveIndex<Array_, Start, End>
81 : [];
82
83type ArraySliceHelper<
84 Array_ extends readonly unknown[],
85 Start extends number = 0,
86 End extends number = Array_['length'],
87 TraversedElement extends Array<Array_[number]> = [],
88 Result extends Array<Array_[number]> = [],
89 ArrayLength extends number = Array_['length'],
90 PositiveS extends number = IsNegative<Start> extends true
91 ? Sum<ArrayLength, Start> extends infer AddResult extends number
92 ? number extends AddResult // (ArrayLength + Start) < 0
93 ? 0
94 : AddResult
95 : never
96 : Start,
97 PositiveE extends number = IsNegative<End> extends true ? Sum<ArrayLength, End> : End,
98> = true extends [IsNegative<PositiveS>, LessThanOrEqual<PositiveE, PositiveS>, GreaterThanOrEqual<PositiveS, ArrayLength>][number]
99 ? []
100 : ArraySliceByPositiveIndex<Array_, TupleMin<[PositiveS, ArrayLength]>, TupleMin<[PositiveE, ArrayLength]>>;
101
102type ArraySliceByPositiveIndex<
103 Array_ extends readonly unknown[],
104 Start extends number,
105 End extends number,
106 Result extends Array<Array_[number]> = [],
107> = Start extends End
108 ? Result
109 : ArraySliceByPositiveIndex<Array_, Sum<Start, 1>, End, [...Result, Array_[Start]]>;