18

In my angular2 project I'm trying to extend the prototype of the string class using typescript. This is my code:

interface String 
{
    startsWith(s:string);
    contains(s:string);
    containsOr(s1:string, s2:string);
}

String.prototype.startsWith = function (s:string):boolean {
    return this.indexOf (s) === 0;
}
String.prototype.contains = function (s:string):boolean {
    return this.indexOf(s) > 1;
}
String.prototype.containsOr = function (s1:string, s2:string):boolean {
    return this.indexOf(s1) > 1 || this.indexOf (s2) > 1;
}

With this code the project compiles (also the content assist of Visual Studio Code assists me) but at run-time I get a 'contains is not defined'.

What I'm doing wrong?

Thanks a lot

PS: this is my tsconfig:

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false,
    "outDir": "wwwroot/app/source/"
  },
  "exclude": [
    "node_modules",
    "bower_components",
    "wwwroot",
    "typings/main",
    "typings/main.d.ts"
  ]
}

EDIT

I noticed that importing the js file in index.html it works, but I don't like this approach.

<script src="app/source/utils/extensions.js"></script>
3
  • Did you import your extensions? If you're using a module loader you're gonna have to check if the code you wrote is actually loaded. Commented Apr 5, 2016 at 17:48
  • Thanks Luka. What do you mean with import? I'm not exporting the class. I updated the question with more details Commented Apr 5, 2016 at 17:57
  • Well in System.js you're going to need to tell the compiler where to find your code. It follows all of your imports and resolves them, loading the contents. That way you can avoid putting all the js files into you html. Commented Apr 5, 2016 at 18:03

2 Answers 2

25

I was able to get it working with no TS errors (1.8.9), Angular2 (2.0.0-beta.12) errors, and working function call using the following template:

tsconfig.json

{
  "compilerOptions": {
  "target": "es5",
  "module": "system",
  "moduleResolution": "node",
  "sourceMap": true,
  "emitDecoratorMetadata": true,
  "experimentalDecorators": true,
  "removeComments": false,
  "noImplicitAny": false
},
"exclude": [
  "node_modules",
  "typings/main",
  "typings/main.d.ts"
  ]
}

Next, create (if one doesn't exist) a global.d.ts file local to your project:

global.d.ts (local to project, not main TS file of same name)

export {}

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

extensions.ts (entire file)

export {}

//don't redefine if it's already there
if (!String.prototype.hasOwnProperty('calcWidth')) {
    String.prototype.calcWidth = function (): number {
      //width calculations go here, but for brevity just return length
      return this.length;
    }
}

Then in your whatever your first System.import(filename) is (mine is main.ts). Just use once:

import './extensions'  //or whatever path is appropriate
... 
...

Now, throughout your app you can use your interface:

var testString = 'fun test';
console.log(testString.calcWidth());

Produces console output:

8

Hope this is helpful.

Sign up to request clarification or add additional context in comments.

Comments

2

Instead of importing the code in html just put this at the top of your code:

import './utils/extensions';

Just replace it with your path to the file.

Here are some more resources on modules and imports:

TypeScript docs

MDN docs

6 Comments

In this way I get the following error: localhost:2068/app/source/utils/extensions.js detected as register but didn't execute.(…)
Can you try exporting String in your extensions.ts? :)
Adding the export work before interface I get a compile error error TS2339: Property 'contains' does not exist on type 'String'. app/source/utils/extensions.ts(15,18): error TS2339: Property 'containsOr' does not exist on type 'String'. The strange thing is that the error is related to contains() and containsOr, and not to startsWith() >.<
That is certainly strange! What happens if you instead write export String at the end of your file?
The compiler gives me Declaration or statement expected. I'm going crazy
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.