17

I want to add extension method format() to String. So my expectation is that I can use String.format wherever in my project. I had followed the guideline of this topic but this not help. I got this error: enter image description here

Can anyone help me?

Thanks in advance.

p.s: I want to add the extension method like I did in angular 1.xx

enter image description here


Edit

use declare global won't get error.

declare global {
interface String {
    format(): string;
}}

String.prototype.format = function () :string {
var result = arguments[0];
for (var i = 0; i < arguments.length - 1; i++) {
    var reg = new RegExp("\\{" + i + "\\}", "gm");
    result = result.replace(reg, arguments[i + 1]);
}
return result;}

How we use String.format('<img alt="{0}" title="{0}" src="{1}" />', name, id); Since format does not require parameters

Community
  • 1
  • 1
jack.pop
  • 683
  • 2
  • 6
  • 21
  • Whatever you have should work. [Playground link](http://www.typescriptlang.org/play/#src=interface%20String%20%7B%0D%0A%20%20%20%20foo()%3A%20number%3B%0D%0A%7D%0D%0A%0D%0AString.prototype.foo%3D%20function()%20%7B%0D%0A%20%20%20%20return%200%3B%0D%0A%7D) – Saravana Apr 27 '17 at 02:22
  • It should be mentioned that is is a terrible practice. Extendng prototypes isn't a good practice either, but String.format is not even a prototype method - the latter would have a benefit of using it like '...'.format() at least. Using globals as namespaces in TypeScript makes no sense. Use modules. If you did this in A1 and switched to A2 and TS, it looks like there's a good chance to stop doing that at last. – Estus Flask Apr 27 '17 at 03:34

2 Answers2

10

For me the following worked in an Angular 6 project using TypeScript 2.8.4.

In the typings.d.ts file add:

interface String {
  format(...args: string[]): string;
}

Note: No need to 'declare global'.

In a new file called string.extensions.ts add the following:

interface String {
  format(...args: string[]): string;
}

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

To use it, first import it:

import '../../string.extensions';

Obviously your import statement should point to the correct path. Inside your class's constructor or any method:

console.log("Hello {0}".format("world"));
Jacques
  • 6,936
  • 8
  • 43
  • 102
  • 8
    Thanks for this, it helped me a lot. In case someone needs it, you can add a shortcut in the tsconfig.json: `"paths": { "@extensions/*": [ "./*.extensions.ts" ] }` and use it like this: `import '@extensions/string';` – Gus Jul 25 '18 at 01:30
  • nice tip on the paths @Gus – Jacques Jul 25 '18 at 07:05
  • This should be the accepted answer. This works with Angular 6 and `declare global` isn't the best way to go about things and `import` is provdided specfically to avoid that. – Suhas Bharadwaj Sep 16 '18 at 10:33
  • 1
    I don't see a `typings.d.ts`, should I create it ? Where ? And how do I include it in the solution ? – Robouste Aug 30 '19 at 09:31
  • 1
    @Robouste you can create it in the src folder. See my post on using it, i.e. "To use it, first import it"... – Jacques Sep 02 '19 at 07:22
  • @Gus's suggestion is great. Just make sure to add `paths` under field `compilerOptions` – Noam Gal Oct 27 '20 at 06:04
9

Based on this playground it works just fine.

It probably doesn't work for you because you're probably using modules (import/export), in that case you need to do that in the global augmentation:

declare global {
    interface String {
        foo(): number;
    }
}

Then you won't get an error when adding foo to the prototype.


Edit

Seems like you want a static function on String, so you need to do this:

declare global {
    interface StringConstructor {
        format(): string;
    }
}

String.format = function (...args: string[]) {
    ...
}

I also added the ...args: string[] to the signature which tells the compiler that the function expects any number of strings as arguments.

Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • Thank you for replying. Use `declare global` won't get error. But how can I declare a method in typescript that I can pass any multiple parameters? `declare global { interface String { format(): string; } } String.prototype.format = function() { var result = arguments[0]; for (var i = 0; i < arguments.length - 1; i++) { var reg = new RegExp("\\{" + i + "\\}", "gm"); result = result.replace(reg, arguments[i + 1]); } return result; }` I could not use: `String.prototype.format('{0}',name, id);` – jack.pop Apr 27 '17 at 02:41
  • 1
    1. Don't put code in comments, instead edit your question and put the code there, then simply comment on an answer and write that the question was updated, 2. Check my revised answer – Nitzan Tomer Apr 27 '17 at 03:16
  • As I wrote in my updated answer, you need to add the `format` function to the `String` class (`StringConstructor`) as static method, and not to the prototype... – Nitzan Tomer Apr 27 '17 at 03:41
  • Your solution is my expectation. Thank you so much. – jack.pop Apr 27 '17 at 03:41