Ask the type system to compute 2 + 2 and it shrugs. Number literal types are opaque tokens. 2 and 3 carry no notion of successor, no way to combine. There is no + operator at the type level and no built-in arithmetic of any kind.

And yet Two Sum computes Target − current for every element of an array, entirely in types. The type system can count one thing: the length of a tuple. Everything numeric in the archive rests on the bridge between a number and a tuple of that length.

The one numeric primitive

A tuple’s length is not the general number you might expect. It is a precise numeric literal type:

type N = [unknown, unknown, unknown]['length'];   // 3, not number

That is the whole foundation. Turn a number N into a tuple of length N, read a tuple’s length back out as a number, and you can do arithmetic by manipulating tuples in between. The first direction is a recursive builder:

type BuildTuple<N extends number, Acc extends unknown[] = []> =
  Acc['length'] extends N
    ? Acc
    : BuildTuple<N, [...Acc, unknown]>;

type T = BuildTuple<3>;   // [unknown, unknown, unknown]

Push unknown onto the accumulator until its length hits the target. Numbers and tuples are now interchangeable, and the operators fall out almost for free.

Addition is concatenation

To add two numbers, build a tuple for each, concatenate them, and measure the result:

type Add<A extends number, B extends number> =
  [...BuildTuple<A>, ...BuildTuple<B>]['length'];

type Sum = Add<2, 3>;   // 5

No carrying, no digits. Concatenation is addition once length is your number line. Spread two tuples of length 2 and 3 into one and the result has length 5. The compiler does this while type-checking.

Subtraction is pattern matching

Subtraction is where Two Sum actually lives. To compute A − B, build a tuple of length A and pattern-match B elements off the front. Whatever remains has length A − B:

type Subtract<A extends number, B extends number> =
  BuildTuple<A> extends [...BuildTuple<B>, ...infer Rest]
    ? Rest['length']
    : never;

type Diff = Subtract<7, 2>;   // 5

[...BuildTuple<B>, ...infer Rest] describes a tuple that starts with B elements and captures everything after as Rest. Match it against a length-A tuple and it peels off the first B slots, handing you the rest. Read its length and you have the difference. (never covers B > A, where the pattern can’t match: the type system’s version of guarding against a negative.)

This is the lookup Two Sum performs. For each element n, it needs Target − n to know what partner to search for, and tuple-subtraction gives it that complement. The “hash map of seen values” is a record keyed by those computed complements, all assembled at type-check time.

Tuples as the universal container

Arithmetic is one use of tuples. Their deeper role is being the type system’s only growable data structure. There are no arrays you can push to, no maps you can mutate. A tuple is it, and spread syntax gives it three jobs depending on which end you work from.

As a stack, you push on one end and pop from it. That is precisely what Valid Parentheses does with its tuple P:

type Push<S extends unknown[], X> = [...S, X];

type Pop<S extends unknown[]> =
  S extends [...infer Rest, infer Top] ? [Rest, Top] : never;

type Pushed = Push<['('], '['>;        // ['(', '[']
type Popped = Pop<['(', '[']>;         // [['('], '[']  rest + the top item

Pushing is a spread onto the end. Popping is a pattern that captures the last element and the remainder separately. Every opening bracket the validator reads gets pushed. Every closing bracket pops the top and checks it matches. The tuple is the stack.

As a counter, you ignore the contents and only ever read ['length']. That is BuildTuple from earlier, used as a loop variable that counts iterations. As a record of state, you store real values in each slot and pattern-match them back out, which is how Candy Crush tracks the board as it collapses runs of three.

One bridge, every number

The pattern to internalize is the round trip. A number becomes a tuple (BuildTuple), you manipulate the tuple with spreads and patterns, then you read ['length'] to get a number back. Addition, subtraction, comparison, and bounded counting all reduce to that loop. The type system never learns to add. It learns to measure, and measuring turns out to be enough.

Pair this with recursion to drive the iteration and template literals to read and write strings, and you have the complete instruction set every experiment in the archive is written in.