Implementing a Type-Level Addition Calculator in TypeScript
This article demonstrates how to build a type-level addition calculator in TypeScript by defining numeric string types, aligning decimal points, using tuple manipulation, and creating a mapping table to perform digit‑wise addition with carry handling, showcasing advanced type‑system techniques.
This article explains how to create a compile‑time addition calculator using TypeScript's type system. It starts by defining the set of numeric characters and an AdvancedNumericCharacters type that restricts numeric strings to valid formats without leading zeros.
Next, a two‑dimensional AddMap is introduced, which maps pairs of digits to their sum and any carry that should be propagated to the next position.
To handle decimal numbers, the SplitByPoint type separates the integer and fractional parts, and AddHelperSplitToArr prepares both operands for further processing. The AddFillZeroHelper then pads the shorter side of each part with zeros using string.PadStart and string.PadEnd so the lengths match.
Because addition proceeds from right to left, the strings are split into tuples of characters and reversed with array.Reverse, yielding AddReverseData. The core digit‑wise addition is performed by StepAdderHelper, which iterates over the reversed tuples, looks up the sum and carry in AddMap, and accumulates the result in a cache tuple, handling carries by inserting a "10" token when needed.
After processing the fractional part, any carry is propagated to the integer part. The integer addition is performed with the same helper, starting with the carry from the fractional addition. The intermediate reversed results are then re‑assembled: the fractional result is reversed back, the decimal point is inserted if needed, and the integer part is concatenated.
The final Add type ties all steps together, exposing a single type that takes two AdvancedNumericCharacters strings and produces their sum as a string literal type. An example usage is shown: type add = Add<"9007199254740991", "9007199254740991">;, which evaluates to the string "18014398509481982".
type Numbers = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; type AdvancedNumericCharacters =
| `${0}.${number}`
| `${Exclude<Numbers, 0>}${number | ""}.${number}`
| `${Exclude<Numbers, 0>}${number | ""}.${number}`
| `${Exclude<Numbers, 0>}${number}`
| `${Numbers}`; type AddMap = [
[ {result: "0"; add: "0"}, {result: "1"; add: "0"}, /* ... */ ],
[ {result: "1"; add: "0"}, {result: "2"; add: "0"}, /* ... */ ],
/* ... up to 99 */
]; type SplitByPoint<S extends AdvancedNumericCharacters> =
string.Includes<S, "."> extends true
? string.Split<S, ".">
: [S, "0"]; type AddHelperSplitToArr<S1 extends AdvancedNumericCharacters, S2 extends AdvancedNumericCharacters> =
[SplitByPoint<S1>, SplitByPoint<S2>]; type AddFillZeroHelper<Data extends [[
`${number}`, `${number}`], [
`${number}`, `${number}`]]> = [
[
string.PadStart<Data[0][0], string.GetStringLength<Data[1][0]>, "0">,
string.PadEnd<Data[0][1], string.GetStringLength<Data[1][1]>, "0">
],
[
string.PadStart<Data[1][0], string.GetStringLength<Data[0][0]>, "0">,
string.PadEnd<Data[1][1], string.GetStringLength<Data[0][1]>, "0">
]
]; type AddReverseData<Data extends [[
`${number}`, `${number}`], [
`${number}`, `${number}`]]> = [
[array.Reverse<string.Split<Data[0][0]>>, array.Reverse<string.Split<Data[0][1]>>],
[array.Reverse<string.Split<Data[1][0]>>, array.Reverse<string.Split<Data[1][1]>>]
]; type StepAdderHelper<
DataLeft extends `${Numbers}`[],
DataRight extends `${Numbers}`[],
Curry extends `${Numbers}` = `0`,
Offset extends number = 0,
ResultCache extends `${number}`[] = []
> = /* recursive implementation that uses AddMap and handles carry */; type MergeResultHelper<Data extends [[
`${Numbers}`[], `${Numbers}`[]], [
`${Numbers}`[], `${Numbers}`[]]]> = /* combines integer and fractional results */; type Add<S1 extends AdvancedNumericCharacters, S2 extends AdvancedNumericCharacters> =
MergeResultHelper<AddReverseData<AddFillZeroHelper<AddHelperSplitToArr<S1, S2>>>>; type add = Add<"9007199254740991", "9007199254740991">; // "18014398509481982"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.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
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.
