Hone logo
Hone
Problems

TypeScript: Implementing an Includes Type

TypeScript's power lies in its ability to create complex and expressive types. One common scenario is to check if a tuple type contains a specific element type. This challenge asks you to create a generic type that mimics the behavior of the Array.prototype.includes() method for tuple types.

This is a foundational type-level programming exercise that helps you understand how to manipulate and query the structure of types, essential for building robust and type-safe TypeScript applications.

Problem Description

You need to create a generic TypeScript type called Includes<T, U> where:

  • T is a tuple type.
  • U is the type to search for within the tuple T.

The Includes<T, U> type should evaluate to true if U is present as an element in the tuple T, and false otherwise.

Key Requirements:

  • The type must work with primitive types (e.g., string, number, boolean).
  • The type must work with object types.
  • The type must correctly handle empty tuples.
  • The type must correctly handle tuples with duplicate elements.

Expected Behavior:

  • If U is found within T, Includes<T, U> should resolve to true.
  • If U is not found within T, Includes<T, U> should resolve to false.

Edge Cases:

  • Empty Tuple: What happens when T is an empty tuple []?
  • Object Comparison: How should object types be compared? (Assume strict equality for objects as well, meaning they must be the exact same reference or structurally identical if they are inferred from literals).

Examples

Example 1:

type Test1 = Includes<[1, 2, 3], 2>;
// Expected Output: true

Explanation: The number 2 is present in the tuple [1, 2, 3].

Example 2:

type Test2 = Includes<[1, 2, 3], 4>;
// Expected Output: false

Explanation: The number 4 is not present in the tuple [1, 2, 3].

Example 3:

type Test3 = Includes<[string, number, boolean], boolean>;
// Expected Output: true

Explanation: The type boolean is present in the tuple [string, number, boolean].

Example 4:

type Test4 = Includes<[], string>;
// Expected Output: false

Explanation: The tuple is empty, so no element can be found.

Example 5:

type Test5 = Includes<[string, number, string], string>;
// Expected Output: true

Explanation: The type string is present, even though it appears multiple times.

Example 6:

type Test6 = Includes<[{ a: 1 }, { b: 2 }], { a: 1 }>;
// Expected Output: false (unless it's the exact same object reference)

Explanation: Type-level comparison typically relies on structural equality or reference equality. Without explicit reference, distinct object literals are considered different.

Constraints

  • The solution must be a single generic type Includes<T, U>.
  • T will always be a tuple type (e.g., [Type1, Type2, ...]).
  • U will be a single type.
  • The solution should be performant for moderately sized tuples.

Notes

This challenge requires you to use conditional types and potentially mapped types or recursive type definitions. Consider how you can iterate through the elements of the tuple T at the type level. Think about the base case (e.g., an empty tuple) and the recursive step (checking the head of the tuple and recursing on the tail).

Loading editor...
typescript