Support for Enumerate and Range
AnatoleLucet opened this issue · comments
I think an Enumerate
and Range
generic could be a nice addition to the Number/Tuple namespace.
I've been using these generics to generate lists of unioned numbers (maybe this could be a tuple instead of a union 🤷) for discriminated unions of objects (e.g. http responses discriminated by status code).
PS amazing work on this lib. I love the overall design and the DX truly looks fantastic!
Great suggestion
@gvergnaud @AnatoleLucet I just realized that one of the issues I opened duplicates this one: #37
I'll close that one and continue the discussion here:
Definition
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N
? Acc[number]
: Enumerate<N, [...Acc, Acc['length']]>;
type IntRange<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>> | T;
Usage
type CustomRange = IntRange<20, 300>; // -> 20 | 21 | ... many more ... | 300
Disclaimer & credit
This type is inspired (99% copied) from this StackOverflow answer by AlexG, with a slight modification to include the last number in the series (| T
). Without this change, IntRange<20, 300>
would match 20
–299
instead or 20
–300
.
Per that last disclaimer, I think it could be more intuitive to include the last/max number. So instead of IntRange<100, 200>
, we could use IntRange<100, 199>
.
We could even make the option of whether to include the end or not a second boolean arg, which I personally think should default to true. With that enabled, if you wanted to keep the min and max values the same and not use the "…99" values, you could do this—
type Informational = IntRange<100, 200, false>;
This would work identically to the previous example. Here is the modified type to support that:
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N
? Acc[number]
: Enumerate<N, [...Acc, Acc['length']]>;
type IntRange<F extends number, T extends number, IncludeEnd = true> = IncludeEnd extends true ? (Exclude<Enumerate<T>, Enumerate<F>> | T) : (Exclude<Enumerate<T>, Enumerate<F>>);
type WithEnd = IntRange<20, 300>; // -> 20 | 21 | ... many more ... | 300
type WithoutEnd = IntRange<20, 300, false>; // -> 20 | 21 | ... many more ... | 299
Hey! This is related to the PR I opened adding a Tuples.Range
function: #40
I think we should implement Unions.Range
in terms of Tuples.Range
Well, here is a PR doing this: #41
(closing because this has been implemented)