Annotated solution
Published August 3, 2026The solution
type Trim<S extends string> = S extends `${Whitespace}${infer R}` ? Trim<R> : S extends `${infer R}${Whitespace}` ? Trim<R> : S
The common wrong answer
type Trim<S extends string> = S extends `${Whitespace}${infer R}${Whitespace}` ? Trim<R> : S
Demanding whitespace at both ends in one pattern fails as soon as only one end has any: `" left"` does not match, so nothing is trimmed. The two ends have to be handled independently.
Line by line
`${Whitespace}${infer R}``Whitespace` is a union, so this pattern is really three patterns tried together — a template literal matches if any member of the union fits the slot.
Trim<R>One character comes off per pass, and the result is fed back in. Both branches recurse into the same type, so leading and trailing whitespace are consumed by the same loop.
Takeaway
A union inside a template literal pattern multiplies the patterns tried. Ordered conditional branches then let you strip one end at a time without writing two separate types.