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