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
}${number | ""}.${number}`
| `${Exclude
}${number | ""}.${number}`
| `${Exclude
}${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
=
string.Includes
extends true
? string.Split
: [S, "0"]; type AddHelperSplitToArr
=
[SplitByPoint
, SplitByPoint
]; type AddFillZeroHelper
= [
[
string.PadStart
, "0">,
string.PadEnd
, "0">
],
[
string.PadStart
, "0">,
string.PadEnd
, "0">
]
]; type AddReverseData
= [
[array.Reverse
>, array.Reverse
>],
[array.Reverse
>, array.Reverse
>]
]; 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
= /* combines integer and fractional results */; type Add
=
MergeResultHelper
>>>; type add = Add<"9007199254740991", "9007199254740991">; // "18014398509481982"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.