Unfortunately since Javascript's string replace() function doesn't let you start from a particular index, and there is no way to do in-place modifications to strings it is really hard to do this as efficiently as you could in saner languages.
- .split().join()isn't a good solution because it involves the creation of a load of strings (although I suspect V8 does some dark magic to optimise this).
- Calling replace()in a loop is a terrible solution because replace starts its search from the beginning of the string every time. This is going to lead to O(N^2) behaviour! It also has issues with infinite loops as noted in the answers here.
- A regex is probably the best solution if your replacement string is a compile time constant, but if it isn't then you can't really use it. You should absolutely not try and convert an arbitrary string into a regex by escaping things.
One reasonable approach is to build up a new string with the appropriate replacements:
function replaceAll(input: string, from: string, to: string): string {
  const fromLen = from.length;
  let output = "";
  let pos = 0;
  for (;;) {
    let matchPos = input.indexOf(from, pos);
    if (matchPos === -1) {
      output += input.slice(pos);
      break;
    }
    output += input.slice(pos, matchPos);
    output += to;
    pos = matchPos + fromLen;
  }
  return output;
}
I benchmarked this against all the other solutions (except calling replace() in a loop which is going to be terrible) and it came out slightly faster than a regex, and about twice as fast as split/join.
Edit: This is almost the same method as Stefan Steiger's answer which I totally missed for some reason. However his answer still uses .join() for some reason which makes it 4 times slower than mine.