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

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.

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.