TypeScript Type‑Level Implementation of Large Integer Addition
This article explains how to perform high‑precision addition of arbitrarily large numbers entirely at compile time using TypeScript's type system, converting strings to digit arrays, adding digits with lookup tables, handling carries, and finally converting the result back to a string.
Result
The final output is a type‑level addition that can handle very large numbers without runtime computation, displayed directly in VSCode's type hinting.
How It Works
Typical TS tricks for addition are limited; this solution uses a systematic approach to support large numbers.
String → Number[]
type DigitRangeMap = [0,1,2,3,4,5,6,7,8,9];
type Digit = DigitRangeMap[number];
type ToDigit<T extends string> = T extends keyof DigitRangeMap ? DigitRangeMap[T] : never;
type ToDigitList<T, R extends any[] = []> =
T extends `${infer First}${infer Rest}`
? ToDigitList<Rest, [ToDigit<First>, ...R]>
: R; // converts string to reversed digit arrayThe conversion stores digits in reverse order to simplify per‑digit addition.
One‑Digit Addition
type AdditionMap = [
[0,1,2,3,4,5,6,7,8,9],
[1,2,3,4,5,6,7,8,9,10],
[2,3,4,5,6,7,8,9,10,11],
...
];
type AddOneDigit<A extends Digit, B extends Digit> = AdditionMap[A][B];Because there are only 100 possible pairs, a lookup table is used for speed; the table is symmetric, so the size is halved by ordering A > B.
Carry Handling
type RoundMap = {10:0;11:1;12:2;13:3;14:4;15:5;16:6;17:7;18:8;19:9};
type Carry<T extends number, R extends number[] = []> =
T extends keyof RoundMap
? [1, [RoundMap[T], ...R]]
: [0, [T, ...R]];Carry returns a tuple where the first element is the carry (0 or 1) and the second element is the updated digit list.
Multi‑Digit Addition
type IncMap = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19];
type Shift<T extends any[]> = T extends [infer First, ...infer Rest] ? Rest : never;
type AddDigitList<A extends any[], B extends any[], ACC extends [0|1, number[]] = [0, []]> =
A['length'] extends 0
? B['length'] extends 0
? ACC[0] extends 1
? AddDigitList<[1], [], [0, ACC[1]]>
: ACC[1]
: AddDigitList<A, Shift<B>, Carry<AddOneDigit<B[0], ACC[0]>, ACC[0]>>
: B['length'] extends 0
? AddDigitList<Shift<A>, B, Carry<AddOneDigit<A[0], ACC[0]>, ACC[0]>>
: AddDigitList<Shift<A>, Shift<B>, Carry<ACC[0] extends 0 ? AddOneDigit<A[0], B[0]> : IncMap[AddOneDigit<A[0], B[0]>], ACC[1]>>;The recursive type walks through both digit arrays, adds corresponding digits with carry, and builds the result.
Number[] → String
type StrDigitRangeMap = ['0','1','2','3','4','5','6','7','8','9'];
type DigitListToString<T, R extends string = ''> =
T extends [infer First, ...infer Rest]
? DigitListToString<Rest, `${R}${First extends number ? StrDigitRangeMap[First] : 'n'}`>
: R;
type Add<A extends string, B extends string> = DigitListToString<AddDigitList<ToDigitList<A>, ToDigitList<B>>>;The final step converts the resulting digit array back to a string, producing the compile‑time sum.
Full Code
/* (Full source code as shown in the article, including all type definitions and helper utilities) */The complete type definitions are provided, allowing developers to paste them into a TypeScript file and see the addition result instantly in the editor.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ByteFE
Cutting‑edge tech, article sharing, and practical insights from the ByteDance frontend team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
