Hone logo
Hone
Problems

Type-Level Arithmetic in TypeScript

This challenge asks you to implement a simplified type-level programming language focused on integer arithmetic within TypeScript. Type-level programming allows you to perform computations and logic at compile time, leading to more robust and performant code by catching errors early. This exercise will give you hands-on experience with conditional types, mapped types, and other advanced TypeScript features to achieve this.

Problem Description

You are tasked with creating a set of TypeScript types that implement basic integer arithmetic operations at the type level. Specifically, you need to implement the following operations:

  • Add<A extends number, B extends number>: Adds two numbers represented as TypeScript types. The result should also be a number type.
  • Subtract<A extends number, B extends number>: Subtracts two numbers represented as TypeScript types. The result should also be a number type.
  • Multiply<A extends number, B extends number>: Multiplies two numbers represented as TypeScript types. The result should also be a number type.
  • Divide<A extends number, B extends number>: Divides two numbers represented as TypeScript types. The result should also be a number type. If B is zero, the type should resolve to never.

The core of this challenge lies in using conditional types and potentially recursive types to perform these operations without runtime execution. You should aim for a solution that is type-safe and handles potential edge cases gracefully.

Examples

Example 1:

type Result = Add<5, 3>; // Expected: 8

Explanation: The Add type should evaluate to the sum of 5 and 3 at compile time.

Example 2:

type Result = Subtract<10, 4>; // Expected: 6

Explanation: The Subtract type should evaluate to the difference of 10 and 4 at compile time.

Example 3:

type Result = Multiply<2, 6>; // Expected: 12

Explanation: The Multiply type should evaluate to the product of 2 and 6 at compile time.

Example 4:

type Result = Divide<12, 3>; // Expected: 4

Explanation: The Divide type should evaluate to the quotient of 12 and 3 at compile time.

Example 5: (Edge Case)

type Result = Divide<5, 0>; // Expected: never

Explanation: Division by zero should result in the never type, indicating an invalid operation.

Constraints

  • All input types A and B must extend number.
  • The output types for Add, Subtract, and Multiply must also extend number.
  • The output type for Divide must be number if the divisor is non-zero, and never if the divisor is zero.
  • The solution should be implemented using only TypeScript's built-in type system features (conditional types, mapped types, etc.). No external libraries are allowed.
  • The solution should be reasonably efficient in terms of type checking time. Excessively complex or recursive type definitions might lead to type checking errors or very long compilation times.

Notes

  • Consider using a recursive approach for Add and Multiply to handle arbitrary number types. A base case is needed to stop the recursion.
  • For Subtract, you might need to handle negative results. The type system doesn't inherently support negative numbers, so you'll need to represent them in a way that allows subtraction to work correctly.
  • For Divide, you'll need to use a conditional type to check if the divisor is zero.
  • Think about how to represent numbers as types. A common approach is to use a recursive type with a base case (e.g., 0, 1, 2, etc.). You can then build up larger numbers from these base cases. However, for this challenge, you can assume the input types are already numbers.
  • This is a challenging problem that requires a good understanding of TypeScript's type system. Don't be afraid to experiment and try different approaches. Start with the simplest operations (e.g., Add) and then build up to the more complex ones.
Loading editor...
typescript