Hone logo
Hone
Problems

Type-Level Integer Addition in TypeScript

This challenge focuses on leveraging TypeScript's advanced type system to perform arithmetic operations not at runtime, but at compile time. You will implement a generic type that can add two "type-level" numbers, representing integers as specific union types. This exercise sharpens your understanding of conditional types, recursive types, and type inference in TypeScript.

Problem Description

The goal is to create a TypeScript type Add<A, B> that takes two type-level numbers, A and B, and returns a new type representing their sum. Type-level numbers will be represented as a specific union of string literal types, where each literal represents a unit. For instance, 0 can be represented by never or an empty union {}, 1 by "1", 2 by "1" | "1", and so on.

Your Add type should be able to:

  • Accept two type-level numbers as generic arguments.
  • Return a type-level number representing the sum of the two input numbers.
  • Handle addition correctly, even for larger numbers.

Key Requirements:

  • Define a representation for type-level integers. A simple and effective way is to use union types of a single string literal, e.g., type One = "1"; type Two = "1" | "1"; type Three = "1" | "1" | "1";.
  • Implement the Add<A, B> generic type.
  • The implementation should rely purely on TypeScript's type system; no runtime code is involved.

Expected Behavior:

When Add<A, B> is used, the resulting type should be equivalent to the sum of the "counts" of "1" literals in A and B.

Edge Cases to Consider:

  • Addition involving zero (represented by never or an empty union).
  • The order of operands should not affect the result (Add<A, B> should be equivalent to Add<B, A>).

Examples

Example 1:

type Num1 = "1"; // Represents 1
type Num2 = "1" | "1"; // Represents 2

type Sum12 = Add<Num1, Num2>;
// Expected type for Sum12: "1" | "1" | "1" (Represents 3)

Explanation: We are adding a type representing 1 with a type representing 2. The result is a type that represents 3.

Example 2:

type Num0 = never; // Represents 0
type Num3 = "1" | "1" | "1"; // Represents 3

type Sum03 = Add<Num0, Num3>;
// Expected type for Sum03: "1" | "1" | "1" (Represents 3)

Explanation: Adding zero to any number should result in that number itself.

Example 3:

type Num5 = "1" | "1" | "1" | "1" | "1";
type Num4 = "1" | "1" | "1" | "1";

type Sum54 = Add<Num5, Num4>;
// Expected type for Sum54: "1" | "1" | "1" | "1" | "1" | "1" | "1" | "1" | "1" (Represents 9)

Explanation: Demonstrates addition of larger numbers.

Constraints

  • The type-level numbers will be represented as union types of "1".
  • The maximum value for the sum is not strictly defined but should be computationally feasible within TypeScript's compilation limits (e.g., not exceeding a few hundred to avoid excessively long compilation times).
  • The representation of zero should be never.

Notes

This challenge requires a deep understanding of conditional types and how to manipulate unions. You might need to think about how to "increment" a type-level number or how to combine two union types in a way that represents addition. Consider using a helper type to increment a number, and then recursively applying it. Think about how to handle the base case of adding zero.

Loading editor...
typescript