koSakano/type-challenges

734 - Inclusive Range

Opened this issue · 0 comments

type Tuple = Array<0>;
type Range = number[];

type Step = [
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
];

/**
 * Tail<[0, 0]> = [0].
 * Tail<[]> = [].
 */
type Tail<T extends Tuple> = T extends [unknown, ...infer Rest] ? Rest : [];

type Next = { current: Tuple; added: Range };
type LowerAndHigher = { lower: Tuple; higher: Tuple };

type UntypedDoStep<
    Current extends Tuple,
    Limit extends number,
    Rest extends Tuple = Step,
    Added extends Range = []
> = Rest extends []
    ? { current: Current; added: Added }
    : Current['length'] extends Limit
    ? { current: Current; added: Added }
    : UntypedDoStep<[0, ...Current], Limit, Tail<Rest>, [...Added, Current['length']]>;

/**
 * DoStep<[], 4> = { current: [0, 0, 0, 0], added: [0, 1, 2, 3] }.
 */
type DoStep<
    Current extends Tuple,
    Limit extends number,
    N = UntypedDoStep<Current, Limit>
> = N extends Next ? N : never;

type UntypedLowerTuples<
    Lower extends number,
    Higher extends number,
    L extends Tuple = [],
    H extends Tuple = []
> = L['length'] extends Lower
    ? { lower: L; higher: H }
    : H['length'] extends Higher
    ? { lower: L; higher: H }
    : UntypedLowerTuples<Lower, Higher, DoStep<L, Lower>['current'], DoStep<H, Higher>['current']>;

/**
 * LowerTuples<3, 4> = { lower: [0, 0, 0], higher: [0, 0, 0, 0] }.
 */
type LowerTuples<
    Lower extends number,
    Higher extends number,
    R = UntypedLowerTuples<Lower, Higher>
> = R extends LowerAndHigher ? R : never;

/**
 * GreaterOrEqual<[0, 0], [0, 0]> = true.
 * GreaterOrEqual<[0, 0], [0, 0, 0]> = false.
 * GreaterOrEqual<[0, 0], [0]> = true.
 * GreaterOrEqual<[], [0]> = false.
 */
type GreaterOrEqual<X extends Tuple, Y extends Tuple> = X extends [...Y, ...Tuple] ? true : false;

/**
 * RangeFrom<[], 5> = [0, 1, 2, 3, 4, 5].
 * RangeFrom<[0, 0], 6> = [2, 3, 4, 5, 6].
 */
type RangeFrom<
    T extends Tuple,
    Higher extends number,
    R extends Range = [],
    S extends Next = DoStep<T, Higher>
> = T['length'] extends Higher
    ? [...R, T['length']]
    : RangeFrom<S['current'], Higher, [...R, ...S['added']]>;

type InclusiveRange<
    Lower extends number,
    Higher extends number,
    Tuples extends LowerAndHigher = LowerTuples<Lower, Higher>
> = GreaterOrEqual<Tuples['higher'], Tuples['lower']> extends false
    ? []
    : RangeFrom<Tuples['lower'], Higher>;