ghaiklor / type-challenges-solutions

Solutions for the collection of TypeScript type challenges with explanations
https://ghaiklor.github.io/type-challenges-solutions/
Creative Commons Attribution 4.0 International
474 stars 57 forks source link

type-challenges-solutions/en/medium-number-range #333

Open utterances-bot opened 1 year ago

utterances-bot commented 1 year ago

Number Range

This project is aimed at helping you better understand how the type system works, writing your own utilities, or just having fun with the challenges.

https://ghaiklor.github.io/type-challenges-solutions/en/medium-number-range.html

jamesbrobb commented 1 year ago

A couple of solutions.

The first creates a Tuple the length of the low number and a Tuple the length of the high number (both populated with numbers), converts them both to unions using T[number] and then uses Exclude to remove the overlap of low and high.

type TupleOfLength<N extends number, R extends number[] = []> = R['length'] extends N ? R : TupleOfLength<N, [...R, R['length']]>

type NumberRange<
  L extends number,
  H extends number,
  LT extends number[] = TupleOfLength<L>,
  HT extends number[] = TupleOfLength<H>
> = Exclude<HT[number] | H, LT[number]>

The second uses the same idea as your solution (starting with nevers and then filling the rest with numbers), but uses a single utility type to achieve it

type NumberRange<L extends number, H extends number, FillWithNums extends boolean = false, 
  R extends number[] = []> = 
    R['length'] extends H ?
      L | R[number] | H:
      NumberRange<
        L,
        H,
        FillWithNums extends true ? true : R['length'] extends L ? true : false,
        [...R, FillWithNums extends true ? R['length'] : never]
      >