The technical term for this sort of thing (a number that's in a specific range) is "dependent types", which is not something that TypeScript attempts to do.
Even if you make a union (either manually or with recursion), it probably won't be much fun, because TypeScript doesn't attempt to track the invariants.
// Error: Type 'number' is not assignable to type 'Hour'.
const q: Hour = 21 + 1;
You could add simple range validation yourself:
function MyComponent({value}: ComponentProps) {
assert(value >= 0 && value <= 24);
You could enforce this more strictly with a newtype, similar to @Lucas Maracaipe's suggestion:
type Hour = number & { readonly __tag: unique symbol };
function validateHour(value: number): Hour {
if (value < 0 || value > 24) {
throw new Error('Hour must be between 0 and 24');
}
return value as Hour;
}
export interface ComponentProps {
title: string;
value: Hour;
}
Finally, if you really wanted, you could use React's prop-types. Prop types are almost completely obsoleted by TypeScript, and I wouldn't recommend them, but their ability to do arbitrary runtime validation is something that TypeScript's type system can't do.