Hone logo
Hone
Problems

Type-Level Sorting in TypeScript

Type-level programming allows us to perform computations at compile time, manipulating types as if they were values. This challenge asks you to implement a type-level sorting algorithm in TypeScript. This is useful for tasks like generating type-safe enums or ensuring that a set of types adheres to a specific order.

Problem Description

You are tasked with creating a type-level sorting function called Sort. This function should take a tuple of types as input and return a new tuple containing the same types, but sorted in ascending order based on a custom comparison function. The comparison function will be provided as a generic type parameter.

Key Requirements:

  • Generic Comparison: The Sort function must accept a generic type Comparison which defines how two types are compared. This Comparison type should be a conditional type that resolves to true if the first type should come before the second type, and false otherwise.
  • Tuple Input: The input to Sort must be a tuple of types.
  • Tuple Output: The output of Sort must also be a tuple of types, containing the input types sorted according to the provided Comparison.
  • No Runtime Execution: The sorting must be performed entirely at compile time. No runtime code should be involved.
  • Handles Duplicates: The sorting algorithm should correctly handle duplicate types in the input tuple. Their relative order in the output should be preserved.

Expected Behavior:

The Sort function should return a new tuple with the types sorted according to the Comparison function. If the input tuple is already sorted, it should return the same tuple.

Edge Cases to Consider:

  • Empty input tuple: Should return an empty tuple.
  • Tuple with a single element: Should return the same tuple.
  • Comparison function that always returns true or false: Should handle these cases gracefully.
  • Complex type structures within the tuple (e.g., unions, intersections). The comparison function should be able to handle these.

Examples

Example 1:

type InputTuple = [string, number, boolean, symbol];

type StringBeforeNumber = (a: any, b: any): true extends (a extends string ? true : b extends number ? true : false) ? true : false ? true : false;

type SortedTuple = Sort<InputTuple, StringBeforeNumber>;

// SortedTuple should be: [string, boolean, symbol, number]

Explanation: The StringBeforeNumber comparison function prioritizes string types over number types. The Sort function uses this comparison to arrange the input tuple accordingly. Boolean and Symbol are placed after string and before number as they are not explicitly compared against.

Example 2:

type InputTuple2 = [number, number, string, boolean];

type NumberBeforeString = (a: any, b: any): true extends (a extends number ? true : b extends string ? true : false) ? true : false ? true : false;

type SortedTuple2 = Sort<InputTuple2, NumberBeforeString>;

// SortedTuple2 should be: [number, number, boolean, string]

Explanation: The NumberBeforeString comparison function prioritizes number types over string types. The Sort function uses this comparison to arrange the input tuple accordingly. Duplicate numbers are preserved in their original order.

Example 3:

type InputTuple3 = [string, string, string];

type StringEqualsString = (a: any, b: any): true extends (a extends string ? true : b extends string ? true : false) ? true : false ? true : false;

type SortedTuple3 = Sort<InputTuple3, StringEqualsString>;

// SortedTuple3 should be: [string, string, string]

Explanation: The StringEqualsString comparison function always returns false. The Sort function should preserve the original order of the input tuple.

Constraints

  • The input tuple can contain up to 10 types. (This is to keep the complexity manageable for type-level computations).
  • The types within the tuple can be any valid TypeScript types (primitive types, unions, intersections, etc.).
  • The Comparison type must be a conditional type that resolves to true or false.
  • The solution must be purely type-level; no runtime code is allowed.
  • The solution should be reasonably performant in terms of TypeScript compilation time. Excessively complex or recursive type definitions may lead to compilation errors or very long compilation times.

Notes

  • This is a challenging problem that requires a good understanding of TypeScript's type system and conditional types.
  • Consider using recursion to implement the sorting algorithm.
  • You may find it helpful to break down the problem into smaller, more manageable sub-problems.
  • Think about how to handle the base cases (empty tuple, single-element tuple) correctly.
  • The comparison function is the key to defining the sorting order. Make sure it's well-defined and consistent.
  • Debugging type-level code can be tricky. Use TypeScript's compiler features (e.g., tsconfig.json with strict: true) to help identify errors.
Loading editor...
typescript