Skip to content

Instantly share code, notes, and snippets.

@shun-shobon
Last active November 11, 2021 15:30
Show Gist options
  • Save shun-shobon/ca7577f3fa1f7ec317ac3f31a97a5858 to your computer and use it in GitHub Desktop.
Save shun-shobon/ca7577f3fa1f7ec317ac3f31a97a5858 to your computer and use it in GitHub Desktop.
Type-level range on TypeScript
type Nat = unknown[];
type Zero = [];
type Suc<N extends Nat> = [...N, unknown];
type Add<N1 extends Nat, N2 extends Nat> = [...N1, ...N2];
type Sub<N1 extends Nat, N2 extends Nat> = N1 extends [...N2, ...infer Ans] ? Ans : Zero;
type NatToNum<N extends Nat> = N["length"];
type _NumToNat<L extends number, TNat extends Nat> = NatToNum<TNat> extends L ? TNat : _NumToNat<L, Suc<TNat>>;
type NumToNat<L extends number> = _NumToNat<L, Zero>;
type _Range<
F extends Nat,
L extends Nat,
X extends Nat,
// Ans is expected to be number[], but TypeScript will throw an error if you change it.
Ans extends unknown[],
> = X extends Sub<L, F> ? Ans : _Range<F, L, Suc<X>, [...Ans, NatToNum<Add<F, X>>]>;
type Range_<F extends number, L extends number> = _Range<NumToNat<F>, NumToNat<L>, Zero, []>;
// Test
// Expect: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
type test1 = Range_<0, 10>;
// Expect: [4, 5, 6, 7, 8, 9, 10, 11, 12]
type test2 = Range_<4, 13>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment