Skip to content
webtype.orgwebtype.org#225 trim-string · par 3

    ↑↓ move · ⏎ open · esc close

    No. 225 · August 2, 2026 · Moderate

    Trim

    Implement `Trim<S>` so it removes whitespace from both ends of a string type. `Whitespace` is in scope and covers spaces, tabs and newlines.

    01

    Try the puzzle yourself

    Par 3

    Puzzle

    trim-string.ts
    type Whitespace = ' ' | '\n' | '\t'
    Stroke 1 of 3Not run yet

    Replace ??? — your solution is checked against the cases below. Tab indents; press Escape then Tab to move focus out.

    Checks

    4
    • Trim<' hello '>
      'hello'
    • Trim<'nospace'>
      'nospace'
    • Trim<'\ttabbed\t'>
      'tabbed'
    • Trim<' '>
      ''

    How a check is judged Exact type equality, not assignability — an intersection is not the same as the flattened object.

    How everyone did

    Fewer than 5 people have solved this one so far. The distribution appears once there is enough of a sample to mean anything.

    Short game

    Fewest characters

    No public scores yet.

    Archive
    02

    Annotated solution

    Published August 3, 2026

    The 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

    1. `${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.

    2. 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.

    Uses