Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend native JavaScript Number object in TypeScript

According to TypeScript docs, extending an already existing Interface is as easy as redeclaring it with new properties, and then provide implementation for those. I've used to this technique to add static method extensions to native JavaScript objects a number of times. This however, doesn't work for member functions.

For example (TypeScript Playground link):

interface Number {
  toPowerOf10: () => string;
}

Number.prototype.toPowerOf10 = (): string => { 
  return this.toExponential();
}

var n: Number = 10000;
n.toPowerOf10();

The above code compiles fine, but at run time, it throws the following exception:

Uncaught TypeError: _this.toExponential is not a function

The culprit seems to be how TypeScript generates the JavaScript code for this scenario:

var _this = this;
Number.prototype.toPowerOf10 = function () {
    return _this.toExponential();
};
var n = 1000;
alert(n.toPowerOf10());

It's obvious _this doesn't have reference to the Number instance here. I'm not sure if I'm doing something wrong, or if extending native objects in this way isn't supported in TypeScript.

like image 314
Uzair Sajid Avatar asked Sep 01 '15 11:09

Uzair Sajid


People also ask

Can we extend type in TypeScript?

Just like object-oriented languages such as Java and C#, TypeScript classes can be extended to create new classes with inheritance, using the keyword extends . In the above example, the Employee class extends the Person class using extends keyword.

How do you use extended interface TypeScript?

Extending Interfaces in TypeScript # Use the extends keyword to extend interfaces in TypeScript, e.g. interface Dog extends Animal {age: number;} . The extends keyword allows us to copy the members from other named types and add new members to the final, more generic interface.

What means T in TypeScript?

'T' is going to be a type declared at run-time instead of compile time. The T variable could be any non-declared variable (I couldn't find a reference, but I would assume any valid set of characters that could be used for a variable names).


1 Answers

It's because you use the arrow notation (=>) to declare the new function and not function. While => may seem like a nice shorthand for the same thing, it and function are not exactly equivalent. In particular, => will do lexical scoping, meaning that this outside of that function will refer to the same thing as this inside that function, which it accomplishes by capturing that local _this in the compiled JavaScript. Here, this is the global scope, as you declare that Number extension there. If this is a browser this will refer to the window object, which of course has no toExponential method.

To accomplish what you want, simply use the following:

declare global {
    interface Number {
          toPowerOf10: () => string;
    }
}

Number.prototype.toPowerOf10 = function() : string {
  return this.toExponential();
}

var n: Number = 10000;
document.write(n.toPowerOf10());
like image 167
JulianR Avatar answered Sep 24 '22 06:09

JulianR