This can be done in typescript. It’s not super well known because of typescripts association with frontend and JavaScript. But typescript is a language with one of the most powerful type systems ever.
Among the popular languages like golang, rust or python typescript has the most powerful type system.
How about a type with a number constrained between 0 and 10? You can already do this in typescript.
type onetonine = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
You can even programmatically define functions at the type level. So you can create a function that outputs a type between 0 to N.
type Range =
A['length'] extends N ? A[number] : Range;
The issue here is that it’s a bit awkward you want these types to compose right? If I add two constrained numbers say one with max value of 3 and another with max value of two the result should be max value of 5. Typescript doesn’t support this by default with default addition. But you can create a function that does this.
// Build a tuple of length L
type BuildTuple =
T['length'] extends L ? T : BuildTuple;
// Add two numbers by concatenating their tuples
type Add =
[...BuildTuple, ...BuildTuple]['length'];
// Create a union: 0 | 1 | 2 | ... | N-1
type Range =
A['length'] extends N ? A[number] : Range;
function addRanges(
a: Range,
b: Range
): Range> {
return (a + b) as Range>;
}
The issue is to create these functions you have to use tuples to do addition at the type level and you need to use recursion as well. Typescript recursion stops at 100 so there’s limits.
Additionally it’s not intrinsic to the type system. Like you need peanno numbers built into the number system and built in by default into the entire language for this to work perfectly. That means the code in the function is not type checked but if you assume that code is correct then this function type checks when composed with other primitives of your program.