Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend Basic Types in TypeScript, Error: "_this is not defined..."

I am trying to rewrite some of my JavaScript code in TypeScript. Some of this code has references to an extension I added to the string object prototype.

String.prototype.format = function () {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        formatted = formatted.replace(
            RegExp("\\{" + i + "\\}", 'g'), arguments[i].toString());
    }
    return formatted;
};

However adding this with type script has been quite challenging.

I have seen examples where you declare an extension of a basic interface then assign an function to the prototype to match the interface and provide your functionality. Like so...

interface String {
    showString: () => string;
}

String.prototype.showString = (): string {
    return this;
};

Except this errors because "_this is not defined..."

The other things I have tried is to create a new class to extend string...

export class MoreString extends string {

}

However this also does not work because you can only extend classes and string/String are not classes but built in types.

What is the simplest way to extend String and access my extension method?

like image 988
QueueHammer Avatar asked Sep 16 '13 18:09

QueueHammer


4 Answers

I ended up running into another issue later in the day that made me see what was happening here. From the top, here it is...

TypeScript is built on top of JavaScript, so like @Nypan says JavaScript is valid TypeScript. Because of this the differences are very easy to overlook.

A JavaScript function like this references the scope that the function executes in with "this".

var f = function (postFix) {return this + postFix};

To add TypeScript syntax you would define types

var f = function (postFix: string): string {return this + postFix};

In both of these cases this refers to the scope of the function just like classic JavaScript. However, things change when we do this...

var f = (postFix: string): string {return this + postFix};
//or more correctly
var f = (postFix: string): string => {return this + postFix};

When you remove the function from in front of the parameters then it is no longer a classic function. It becomes a "Fat Arrow" function, apparently even with out using the "=>" syntax. In the examples above "this" now refers to the class that the function exists in like in C#.

In my attempt to assign a function to the prototype of string I omitted the function keyword so it was interpreted as a "Fat Arrow" function and tries to bind this to the scope of the class. However the function dose not exist in a class and causes the error "_this is not defined".

When I add the "function" keyword, the function is interpreted as I intended and works correctly.

interface String {
    format: () => string;
}

String.prototype.format = function () : string {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        formatted = formatted.replace(
            RegExp("\\{" + i + "\\}", 'g'), arguments[i].toString());
    }
    return formatted;
};
like image 190
QueueHammer Avatar answered Nov 18 '22 22:11

QueueHammer


In exactly similiar case i do it like that:

interface String {
    endsWith(str);
    startsWith(str);

}

This is just to satisfy the compiler. You implement the methods exactly like in javascript.

Hope that helps.

like image 45
stride Avatar answered Nov 18 '22 21:11

stride


I think that this is the same thing that stride was getting at but you simply extend it in javascript (javascript is valid typescript) and then interface the new functionality.

Short example:

String.prototype.myExtension = function () {
   return this + " something."
};

interface String {
    myExtension : () => string;
}

alert("test".myExtension());
like image 2
Nypan Avatar answered Nov 18 '22 22:11

Nypan


You need to extend the String interface like this:

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

and you need to implement like this

module Utilities {
    String.prototype.stringFormat = function (): string {
        var args = arguments;
        return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) {
            if (m == "{{") { return "{"; }
            if (m == "}}") { return "}"; }
            return args[n];
        });
    }
}

implementation source: Equivalent of String.format in jQuery

like image 1
Thalles Noce Avatar answered Nov 18 '22 22:11

Thalles Noce