1 | import type {BuildTuple} from './internal';
|
2 | import type {Subtract} from './subtract';
|
3 |
|
4 | /**
|
5 | Generate a union of numbers.
|
6 |
|
7 | The numbers are created from the given `Start` (inclusive) parameter to the given `End` (exclusive) parameter.
|
8 |
|
9 | You skip over numbers using the `Step` parameter (defaults to `1`). For example, `IntRange<0, 10, 2>` will create a union of `0 | 2 | 4 | 6 | 8`.
|
10 |
|
11 | Note: `Start` or `End` must be non-negative and smaller than `1000`.
|
12 |
|
13 | Use-cases:
|
14 | 1. This can be used to define a set of valid input/output values. for example:
|
15 | ```
|
16 | type Age = IntRange<0, 120>;
|
17 | type FontSize = IntRange<10, 20>;
|
18 | type EvenNumber = IntRange<0, 11, 2>; //=> 0 | 2 | 4 | 6 | 8 | 10
|
19 | ```
|
20 | 2. This can be used to define random numbers in a range. For example, `type RandomNumber = IntRange<0, 100>;`
|
21 |
|
22 | @example
|
23 | ```
|
24 | import type {IntRange} from 'type-fest';
|
25 |
|
26 | // Create union type `0 | 1 | ... | 9`
|
27 | type ZeroToNine = IntRange<0, 10>;
|
28 |
|
29 | // Create union type `100 | 200 | 300 | ... | 900`
|
30 | type Hundreds = IntRange<100, 901, 100>;
|
31 | ```
|
32 | */
|
33 | export type IntRange<Start extends number, End extends number, Step extends number = 1> = PrivateIntRange<Start, End, Step>;
|
34 |
|
35 | /**
|
36 | The actual implementation of `IntRange`. It's private because it has some arguments that don't need to be exposed.
|
37 | */
|
38 | type PrivateIntRange<
|
39 | Start extends number,
|
40 | End extends number,
|
41 | Step extends number,
|
42 | Gap extends number = Subtract<Step, 1>, // The gap between each number, gap = step - 1
|
43 | List extends unknown[] = BuildTuple<Start, never>, // The final `List` is `[...StartLengthTuple, ...[number, ...GapLengthTuple], ...[number, ...GapLengthTuple], ... ...]`, so can initialize the `List` with `[...StartLengthTuple]`
|
44 | EndLengthTuple extends unknown[] = BuildTuple<End>,
|
45 | > = Gap extends 0 ?
|
46 | // Handle the case that without `Step`
|
47 | List['length'] extends End // The result of "List[length] === End"
|
48 | ? Exclude<List[number], never> // All unused elements are `never`, so exclude them
|
49 | : PrivateIntRange<Start, End, Step, Gap, [...List, List['length'] ]>
|
50 | // Handle the case that with `Step`
|
51 | : List extends [...(infer U), ...EndLengthTuple] // The result of "List[length] >= End", because the `...BuildTuple<Gap, never>` maybe make `List` too long.
|
52 | ? Exclude<List[number], never>
|
53 | : PrivateIntRange<Start, End, Step, Gap, [...List, List['length'], ...BuildTuple<Gap, never>]>;
|