Is it possible to restrict number to a certain range
If You have small range, you can always write something like:
type MyRange = 5|6|7|8|9|10
let myVar:MyRange = 4; // oops, error :)
Of course it works just for integers and is ugly as hell :)
No it's not possible. That kind of precise type constraint is not available in typescript (yet?)
Only runtime checks/assertions can achieve that :(
Yes, it's possible BUT:
The 1st. Solution Will be a dirty Solution The 2nd. Solution Will be partial (from x to y where y is a small number, 43 in my case) The 3rd. Solution will be a Complete solution but really advance with Transformers, Decorators, etc.
1. Dirty solution ( the easiest and fast way first ) using @Adam-Szmyd solution:
type RangeType = 1 | 2 | 3
if you need an extensive range, just print and copy/paste:
// Easiest just incremental
let range = (max) => Array.from(Array(max).keys()).join(" | ");
console.log('Incremental')
console.log(range(20))
// With range and steps
let rangeS = (( min, max, step) => Array.from( new Array( max > min ? Math.ceil((max - min)/step) : Math.ceil((min - max)/step) ), ( x, i ) => max > min ? i*step + min : min - i*step ).join(" | "));
console.log('With range and steps')
console.log(rangeS(3,10,2))
You may be tented of doing things like this
const data = [1, 2, 4, 5, 6, 7] as const;
type P = typeof data[number];
but instead using functions
const rangeType20 = Array.from(Array(20).keys()) as const;
But at the moment this doesn't work, only work if is a literal. Even the error is not quite correct.
2. Partial solution (source)
type PrependNextNum<A extends Array<unknown>> = A['length'] extends infer T ? ((t: T, ...a: A) => void) extends ((...x: infer X) => void) ? X : never : never;
type EnumerateInternal<A extends Array<unknown>, N extends number> = { 0: A, 1: EnumerateInternal<PrependNextNum<A>, N> }[N extends A['length'] ? 0 : 1];
export type Enumerate<N extends number> = EnumerateInternal<[], N> extends (infer E)[] ? E : never;
export type Range<FROM extends number, TO extends number> = Exclude<Enumerate<TO>, Enumerate<FROM>>;
type E1 = Enumerate<43>;
type E2 = Enumerate<10>;
type R1 = Range<0, 5>;
type R2 = Range<0, 43>;
3. Complete solution but really advance with Transformers
, Decorators
, etc.
Using the functions on the first solution, you could replace at compiletime
by the values, using transformer. Similarly, but on runtime
using decorators.