Search code examples
typescriptstring-interpolation

Typescript String.format does not exist


I have a string const where I have to replace two words, like this:

public static readonly MY_STRING: string = 'page={0}&id={1}';

0 and 1 have to be replaced with other strings. I have read about String.format in different answers, where they suggest to supply an implementation like this:

if (!String.prototype.format) {
  String.prototype.format = function() {
    var args = arguments;
    return this.replace(/{(\d+)}/g, function(match, number) { 
      return typeof args[number] != 'undefined'
        ? args[number]
        : match
      ;
    });
  };
}

but when I do String.format it tells me

Property 'format' does not exist on type 'String'

What is the proper way to use String interpolation/substitution in this case? With format I'd do something like this:

 MY_STRING.format(page, id)

How can I achieve this?


Solution

  • It is considered bad practice to modify native prototypes like String. Since there's no standard or agreed-upon format() method for strings in JavaScript, adding your own could lead to unexpected behavior in any code that runs in the same runtime. Your implementation even checks for an existing String.prototype.format first, which means if someone gets there first with a different implementation, then you could be the one with unexpected behavior.

    There's absolutely nothing wrong with just having a stringFormat function sitting around that you use, like this:

    function stringFormat(template: string, ...args: any[]) {
        return template.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] != 'undefined'
                ? args[number]
                : match
                ;
        });
    };
    
    const myString: string = 'page={0}&id={1}';
    const formattedWithFormat = stringFormat(myString, 123, 456);
    console.log(formattedWithFormat); // page=123&id=456
    

    Also, JavaScript has template literals which provide essentially the same functionality:

    const myTemplate = (page: number, id: number) => `page=${page}&id=${id}`;
    const formattedWithTemplate = myTemplate(123, 456);
    console.log(formattedWithTemplate); // page=123&id=456
    

    If you are intent on modifying the prototype of String and the previous warnings didn't dissuade you, then you could use the global augmentation or module augmentation approach to allow TypeScript to recognize that you expect string values to have a format() method:

    /* 🐉 here be dragons 🐲 */
    interface String {
        format(...args: any[]): string;
    }
    String.prototype.format = function (...args) { return stringFormat(String(this), ...args) };
    console.log(myString.format(123, 789)); // page=123&id=789
    

    but hopefully you will use one of the other solutions.


    Okay, hope that helps; good luck!

    Playground link