(EXPERIMENTAL! MADE FOR FUN!) Type-level natural integers powering advanced types. Inspired by Rust's const generics.
Code built from this repository may contain traces of peanuts.
Please be advised that the use of this library may incur the following side effects:
- mystifying errors traces;
- undefined behavior when using integers above 0x55f;
- increased transpilation times;
- distrust or even anger from coworkers.
Constant-sized immutable array.
const arr = new SizedArray<string, Int<2>>("a", "b")
// Safe array access
const inBounds: string = arr.at(1) // ✔️ (no undefined!)
const outOfBounds: string = arr.at(2) // ❌ Type 'string | undefined' is not assignable to type 'string'
// Keeps track of length when creating new arrays
const arr2 = arr.push("c")
const len: 3 = arr2.lengthA natural integer between known bounds.
const _ = BoundedInt.range(4, 8)
const five = _(5)
// Compile-time comparison
const isGreaterThan4: true = five.greaterThan(4)
// Addition keeps track of range
const seven = five.add(int(2))
const sumGreaterThan6: true = seven.greaterThan(6)Take a look at the definition of those types to get a feel for what is possible.
The following types represent type-level natural integers.
AnyIntis the type of all type-level natural integersInt<1>is the type-level natural integer representing 1Succ<T>,Prec<T>are respectively the integers coming after and beforeTSum<A, B>is the type that represents the sum of integersAandB; similarly,Diffis for substraction andMulfor multiplicationRange<A, B>is the type that represents all integers fromAtoB:A | Succ<A> | Succ<Succ<A>> | ... | Prec<B> | B
The chosen representation 🥜🥜🥜 should not be taken for granted. These integers should be treated as opaque types.
The following types narrow the number type.
AsNumber<T>is the narrowed type of anumberthat matches the integerT, e.g.AsNumber<Int<1>>is the type1Natural<n>checks thatnis a natural integer and anumber, e.g.Natural<1>is equivalent to1, butNatural<-1.5>isneverLowerThan<T, n>checks thatnis a natural integer and lower thanT, e.g.Lower<Int<3>, 2>is the type2butLower<Int<3>, 4>isneverGreaterThan<T, n>checks thatnis a natural integer and anumberand greater thanT, e.g.GreaterThan<Int<2>, 3>is equivalent to3butGreaterThan<Int<2>, 1>isneverInRange<A, B>is a combination ofLowerThanandGreaterThan
Sometimes, a method calls for a type-level integer value (because type inference has limits), i.e. a constant integer. It only makes sense to use constant expressions to create a type-level integer value.
const a: Int<2> = int(2)
const a: Int<2> = int(1 + 1) // ❌ Argument of type 'number' is not assignable to parameter of type <redacted>The value of that integer can be read back with number.
number(a) // === 2