Skip to content

Instantly share code, notes, and snippets.

@fredrare
Created December 6, 2024 21:34
Show Gist options
  • Save fredrare/1cacbacecbfdc2d992fa8c76f91f64d0 to your computer and use it in GitHub Desktop.
Save fredrare/1cacbacecbfdc2d992fa8c76f91f64d0 to your computer and use it in GitHub Desktop.
Small and simple generic number range implementation in TypeScript
type NextDigit = [1, 2, 3, 4, 5, 6, 7, 8, 9]
type Split<Str> = Str extends `${infer Head extends number}${infer Tail}` ? [Head, ...Split<Tail>] : []
type Increase<X extends number[]> = X extends [...infer Rest extends number[], infer Last extends number] ?
Last extends 9 ? [...Increase<Rest>, 0] : [...Rest, NextDigit[Last]]
: [1]
type TupleToString<T extends number[]> =
T extends [infer First extends number, ...infer Rest extends number[]]
? `${First}${TupleToString<Rest>}`
: ""
type NumberRange<Start extends number, End extends number> = Start extends End ?
End :
TupleToString<Increase<Split<`${Start}`>>> extends `${infer Num extends number}` ?
Start | NumberRange<Num, End> : never
// Works fine with small ranges
type Hour = NumberRange<0, 23>
// We can't use large ones though, because TypeScript throws an error.
// But we can bypass this by making a union out of the unions so that the recursion depth is smaller.
// This is far from ideal or elegant, so this is open for improvement.
type Minute = NumberRange<0, 29> | NumberRange<30, 59>
type Second = NumberRange<0, 29> | NumberRange<30, 59>
// This works just fine
const hours: Hour = 12
// This doesn't because the operation returns a `number`
const minutes: Minute = 12 + 12
// Unless we do this, of course
const seconds: Second = 12 + 12 as Second
@fredrare
Copy link
Author

fredrare commented Dec 6, 2024

You can try this out in the playground. The result is a union type, so that's not ideal. Using it for small ranges should be just fine though.

I made this to kinda solve a use case for TypeScript #54925.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment