531. String to Union
531. String to Union
Problem
Implement the StringToUnion type. Type takes a string argument. The output should be a union of input letters.
type Test = "123"
type Result = StringToUnion<Test> // expected to be "1" | "2" | "3"Solution
type StringToUnion<S extends string> =
S extends `${infer First}${infer Rest}`
? First | StringToUnion<Rest>
: neverDeep Dive
How It Works
This solution leverages TypeScript's template literal types and conditional types to recursively decompose a string into its individual characters:
Pattern Matching:
S extends \{infer Rest}`uses template literal inference to extract the first character (First) and the remaining string (Rest`).Union Building: For each recursion step, we add
Firstto the union withFirst | StringToUnion<Rest>.Base Case: When
Sis empty, the pattern match fails, returningnever. SinceT | never = T, this cleanly terminates the recursion.
Step-by-Step Example
For StringToUnion<"abc">:
StringToUnion<"abc">
= "a" | StringToUnion<"bc">
= "a" | "b" | StringToUnion<"c">
= "a" | "b" | "c" | StringToUnion<"">
= "a" | "b" | "c" | never
= "a" | "b" | "c"Why infer Works With Single Characters
When you use ${infer First}${infer Rest} on a string:
- TypeScript is greedy from the left, so
Firstalways captures exactly one character Restcaptures everything else (including empty string)
Edge Cases
type Empty = StringToUnion<""> // never
type Single = StringToUnion<"x"> // "x"
type Spaces = StringToUnion<"a b"> // "a" | " " | "b"Key Takeaways
Template Literal Inference:
${infer X}${infer Y}is the standard pattern for string decomposition in TypeScript's type system.Recursive Union Construction: Building unions recursively with
X | RecursiveType<Rest>is a common pattern for transforming sequences.neveras Identity: In union types,neveracts as the identity element — adding it changes nothing, making it perfect for base cases.Character-Level Operations: This pattern is foundational for many string manipulation types like
Split,Join, and character filtering.
