Skip to content
webtype.orgwebtype.org

    ↑↓ 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