Hone logo
Hone
Problems

Implementing Variadic Tuple Types in TypeScript

Variadic tuple types allow you to work with tuples of variable length, providing a powerful way to handle data structures where the number of elements isn't known at compile time. This challenge focuses on creating utility types that manipulate these variadic tuples, enabling you to perform operations like extracting the first element, concatenating tuples, and checking if a tuple contains a specific type. Successfully implementing these types will enhance your ability to write more flexible and type-safe code.

Problem Description

You are tasked with creating a set of TypeScript utility types that operate on variadic tuple types. A variadic tuple type is represented as a tuple where the number of elements is not fixed. You need to implement the following utility types:

  1. First<T>: Extracts the first element of a tuple T.
  2. Concat<T extends readonly [...any[]], U extends readonly [...any[]]>: Concatenates two tuples T and U into a single tuple.
  3. Contains<T extends readonly [...any[]], U>: Checks if a tuple T contains at least one element of type U. Returns true if it does, false otherwise.

These utility types should be implemented using conditional types and tuple manipulation techniques. The goal is to ensure type safety and provide compile-time guarantees.

Key Requirements:

  • The utility types must work correctly for tuples of any length (including empty tuples).
  • The Concat type must preserve the order of elements from both input tuples.
  • The Contains type should accurately determine if the tuple contains an element of the specified type.
  • All types must be defined using only TypeScript's built-in type features (no external libraries).

Expected Behavior:

  • First<[1, 2, 3]> should evaluate to 1.
  • First<[]> should evaluate to never.
  • Concat<[1, 2], [3, 4]> should evaluate to [1, 2, 3, 4].
  • Concat<[1, 2], []> should evaluate to [1, 2].
  • Concat<[], [3, 4]> should evaluate to [3, 4].
  • Contains<[1, 2, 3], 2> should evaluate to true.
  • Contains<[1, 2, 3], 4> should evaluate to false.
  • Contains<[], 1> should evaluate to false.

Examples

Example 1:

Input: First<[string, number, boolean]>
Output: string
Explanation: The first element of the tuple is a string.

Example 2:

Input: Concat<[1, 2], [3, 4]>
Output: [1, 2, 3, 4]
Explanation: The two tuples are concatenated in order.

Example 3:

Input: Contains<[1, 'hello', true], 'hello'>
Output: true
Explanation: The tuple contains the string 'hello'.

Example 4: (Edge Case - Empty Tuple)

Input: First<[]>
Output: never
Explanation: An empty tuple has no first element, so the type is never.

Constraints

  • All input tuples will be of primitive types (number, string, boolean, etc.). No complex objects within the tuples.
  • The Contains type should only consider the type of the element, not its value.
  • Performance is not a primary concern for this challenge; focus on correctness and type safety.
  • The utility types must be defined using only TypeScript's built-in type features.

Notes

  • Consider using conditional types to handle different cases based on the length of the tuples.
  • The readonly keyword is important for ensuring type safety when working with tuples.
  • The ... spread operator can be helpful for manipulating tuples.
  • Think about how to handle edge cases, such as empty tuples, gracefully. never is often a suitable type for representing the absence of a value.
  • Start with the First type, as it's the simplest, and then build upon that to implement Concat and Contains.
Loading editor...
typescript