/** * @fileoverview Types for doing math in TS, by representing each natural number * as a tuple with n elements, and exploiting its ability to track a tuple's * length as a number literal type. */ import type { UnionToIntersection } from "type-fest"; /** * Creates a type representing a range of numbers from Min to Max (inclusive) */ export type NumericRange< Min extends number, Max extends number, Arr extends number[] = [], Curr extends number = never, > = Arr["length"] extends Max ? Arr[number] | Max : NumericRange< Min, Max, [...Arr, Arr["length"]], Arr["length"] extends Min ? Arr["length"] : Curr >; export type Permutations = PermuteRest< AllShifts >; type PermuteRest = T extends [infer F, ...infer R] ? [F, ...PermuteRest>] : []; type AllShifts< T extends readonly unknown[], N extends Nat = TupleLengthNat, > = N extends Zero ? T : Shift | AllShifts>; type Shift = T extends readonly [ infer F, ...infer R, ] ? N extends Zero ? T : Shift<[...R, F], Dec> : []; // Specialized implementation of Number2Nat for tuples. // This version lets Permutations typecheck. type TupleLengthNat = T extends [ infer _F, ...infer R, ] ? Succ> : Zero; type Zero = []; type Nat = [...1[]]; type Succ = [...N, 1]; type Dec = N extends [1, ...infer T] ? T : never; type Nat2Number = N["length"]; type Number2Nat = I extends Nat2Number ? N : Number2Nat>; type NumericToNat = I extends `${infer T extends number}` ? Number2Nat : never; type Min2 = ((...args: N) => any) extends ( ...args: M ) => any ? N : M; type Min = T extends [ infer M, infer N, ...infer R extends Nat[], ] ? //@ts-ignore Min2> : T extends [infer M extends Nat, infer N extends Nat] ? Min2 : T extends [infer M] ? M : Zero; type Max2 = ((...args: N) => any) extends ( ...args: M ) => any ? M : N; type MaxOfUnion = Nat2Number< Parameters< UnionToIntersection< { [K in It]: (...it: readonly [...Number2Nat]) => any }[It] > > >; type MinOfUnion = Exclude> extends never ? It : MinOfUnion>>; type Add = readonly [...N, ...M]; type Multiply = M extends Zero ? Zero : Add>>; type Subtract = M extends Zero ? N : Subtract, Dec>;