Hone logo
Hone
Problems

Type-Level Binary Search in TypeScript

Master the intricacies of TypeScript's type system by implementing a binary search algorithm entirely at the type level. This challenge will test your understanding of conditional types, tuple manipulation, and recursive type definitions. Successfully implementing this will demonstrate a deep grasp of advanced TypeScript features applicable to compile-time data validation and meta-programming.

Problem Description

Your task is to create a TypeScript type, let's call it TypeLevelBinarySearch<Arr extends readonly unknown[], Target, Index extends number = 0>, that determines if a Target value exists within a sorted tuple Arr. The type should return the Index of the Target if found, or -1 if not found.

The search should be performed using a binary search approach, meaning you'll recursively narrow down the search space by comparing the Target with the middle element of the current sub-tuple.

Key Requirements:

  • The input Arr must be a readonly tuple.
  • The Target can be any type that can be reasonably compared (e.g., numbers, strings).
  • The search is case-sensitive for strings and exact for other types.
  • The Arr is assumed to be sorted in ascending order.
  • The type should return the Index (a number literal type) of the Target if found.
  • If the Target is not found, the type should return -1.
  • The Index parameter is an internal helper to track the offset from the original array's start.

Expected Behavior:

The type will take the Arr, Target, and optionally the current Index offset. It will:

  1. Determine the middle index of the current tuple.
  2. Compare the Target with the element at the middle index.
  3. If they match, return the current Index plus the middle index.
  4. If Target is less than the middle element, recursively search the left half.
  5. If Target is greater than the middle element, recursively search the right half, adjusting the Index offset.
  6. If the tuple becomes empty during the search, the Target is not found, and -1 should be returned.

Examples

Example 1:

// Input:
type Array1 = [1, 3, 5, 7, 9, 11, 13];
type Target1 = 7;

// Expected Output:
type Result1 = TypeLevelBinarySearch<Array1, Target1>; // Should be 3

Explanation: The TypeLevelBinarySearch type will find 7 at index 3 in [1, 3, 5, 7, 9, 11, 13].

Example 2:

// Input:
type Array2 = ["apple", "banana", "cherry", "date"];
type Target2 = "grape";

// Expected Output:
type Result2 = TypeLevelBinarySearch<Array2, Target2>; // Should be -1

Explanation: The TypeLevelBinarySearch type will not find "grape" in ["apple", "banana", "cherry", "date"] and will return -1.

Example 3:

// Input:
type Array3 = [2, 4, 6, 8];
type Target3 = 4;

// Expected Output:
type Result3 = TypeLevelBinarySearch<Array3, Target3>; // Should be 1

Explanation: The TypeLevelBinarySearch type will find 4 at index 1 in [2, 4, 6, 8].

Example 4 (Edge Case: Empty Array):

// Input:
type Array4 = [];
type Target4 = 5;

// Expected Output:
type Result4 = TypeLevelBinarySearch<Array4, Target4>; // Should be -1

Explanation: An empty array cannot contain the target, so -1 is returned.

Constraints

  • The input Arr will be a readonly tuple.
  • The elements within Arr will be comparable to the Target.
  • The Arr will be sorted in ascending order.
  • The maximum length of Arr is expected to be within reasonable TypeScript recursion depth limits (typically around 50-100 elements for complex recursive types).

Notes

  • You'll need to utilize conditional types extensively.
  • Consider how to extract elements from tuples and slice them effectively at the type level.
  • Helper types for calculating the middle index and for splitting tuples will be invaluable.
  • Be mindful of the number type and its literal type representations for indices.
  • The comparison logic (<, >, ===) needs to be carefully implemented using conditional types. You might need helper types for type-level comparisons.
Loading editor...
typescript