Skip to content
webtype.orgwebtype.org#228 replace-string · par 3

    ↑↓ move · ⏎ open · esc close

    No. 228 · August 5, 2026 · Moderate

    Replace

    Implement `Replace<S, From, To>` so it replaces the **first** occurrence of `From` in `S` with `To`. An empty `From` replaces nothing.

    01

    Try the puzzle yourself

    Par 3

    Puzzle

    replace-string.ts
    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
    • Replace<'hello world', 'world', 'there'>
      'hello there'
    • Replace<'abc', 'x', 'y'>
      'abc'
    • Replace<'aaa', 'a', 'b'>
      'baa'
    • Replace<'abc', '', 'x'>
      'abc'

    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 6, 2026

    The solution

    type Replace<S extends string, From extends string, To extends string> =
      From extends ''
        ? S
        : S extends `${infer H}${From}${infer T}`
          ? `${H}${To}${T}`
          : S

    The common wrong answer

    type Replace<S extends string, From extends string, To extends string> =
      S extends `${infer H}${From}${infer T}` ? `${H}${To}${T}` : S

    Correct for every input except an empty `From`. The empty string sits between any two characters, so the pattern matches with `H` empty and inserts `To` at the front — `Replace<"abc", "", "x">` becomes `"xabc"`.

    Line by line

    1. From extends '' ? S

      The guard has to come first. Once the template pattern is reached an empty `From` has already made the match succeed, and there is no way to distinguish it afterwards.

    2. `${infer H}${From}${infer T}`

      Inference is greedy from the left, so `H` takes the shortest prefix that still lets the rest match. That is precisely why only the *first* occurrence is replaced.

    Takeaway

    The empty string is the null of template literal types: it matches everywhere and silently breaks patterns that assume a match means something was found.

    Uses