Hone logo
Hone
Problems

Implementing a Replace Type Utility in TypeScript

TypeScript's utility types are powerful tools for manipulating and transforming types. This challenge asks you to implement a custom utility type called Replace that replaces all occurrences of a specific type within a union type with another type. This is useful for refining complex type definitions and creating more specialized types based on existing ones.

Problem Description

You need to create a TypeScript type Replace<T, Old, New> that takes three type parameters:

  • T: The union type you want to modify.
  • Old: The type you want to replace within T.
  • New: The type you want to replace Old with.

The Replace type should return a new union type where all instances of Old within T are replaced with New. If Old does not exist in T, the original T should be returned unchanged.

Key Requirements:

  • The solution must be a valid TypeScript type definition.
  • The Replace type must handle union types correctly.
  • The Replace type must not modify the original type T.
  • The Replace type must correctly handle cases where Old is not present in T.

Expected Behavior:

The type Replace<T, Old, New> should produce a new type that is structurally equivalent to T, except that all occurrences of Old have been replaced with New.

Edge Cases to Consider:

  • T is not a union type (e.g., a primitive type, an intersection type).
  • Old is never present in T.
  • Old appears multiple times in T.
  • New is a more complex type than Old.
  • Old and New are the same type.

Examples

Example 1:

type T1 = "a" | "b" | "c";
type Expected1 = Replace<T1, "b", "d">;
// Expected1: "a" | "d" | "c"

Explanation: The type "b" in the union T1 is replaced with "d", resulting in the new union "a" | "d" | "c".

Example 2:

type T2 = 1 | 2 | "hello";
type Expected2 = Replace<T2, 2, 3>;
// Expected2: 1 | 3 | "hello"

Explanation: The number 2 in the union T2 is replaced with the number 3.

Example 3:

type T3 = "a" | "b" | "c";
type Expected3 = Replace<T3, "d", "e">;
// Expected3: "a" | "b" | "c"

Explanation: Since "d" is not present in T3, the original type T3 is returned unchanged.

Example 4:

type T4 = string | number | string;
type Expected4 = Replace<T4, string, boolean>;
// Expected4: boolean | number | boolean

Explanation: All occurrences of string are replaced with boolean.

Constraints

  • The solution must be a valid TypeScript type definition.
  • The solution should be reasonably efficient. While performance isn't the primary concern, avoid unnecessarily complex or inefficient type manipulations.
  • The solution should be readable and well-formatted.
  • The solution must work with any valid TypeScript types for T, Old, and New.

Notes

Consider using conditional types and distributive conditional types to achieve the desired behavior. Think about how to iterate through the union type T and conditionally replace the Old type with New. Remember that TypeScript's type system is structural, so focus on the shape of the types rather than their names.

Loading editor...
typescript