Home > Enterprise >  Override builtin function is Typescript
Override builtin function is Typescript

Time:12-30

I am trying to override the 'toString' function in Number object. This means that if I do:

var a = 4564645;
console.log(a.toString(36))

Expected result:

Value: 2pu3p, radix: 36

What i tried:

(window as any).Number.prototype._toString = Number.prototype.toString;
(window as any).Number.prototype.toString = (radix) => {
    let val = this._toString.call(this, radix);
    console.log("value: "   val   ", "Radix: "   radix)
    return val;
}

I think the problem is with 'this', what should I do?

CodePudding user response:

Before I continue, are you sure this is a good idea? Because it is almost certainly a very bad idea for a great number of reasons.

Every bit of code in your entire codebase, including dependencies that you don't directly control, assumes that the built ins work in a specific and standard way. If you change that, then really bad and strange things may happen.

You may think logging a a number isn't bad, but if some code in a dependency processes thousands of numbers in a loop, which should be pretty fast, then you now generate thousands of log messages. Now imagine your in a nodejs server, and you write console.log output to a log file or cloud based logging service. Now you are generating many megabytes of useless logs. And your app becomes very slow, and then the AWS bill comes in and your usage has sky rocketed and now you owe them a fortune. All because in one little case, you wanted to know some specific number gets turned into a string.

Or what if someone else had the same idea? They override this in the same way, and you clobber that code's override of Number.prototype._toString. Now that code breaks, or yours does, in a race condition won by the code that happened to load second.

So... be careful here.


That said, it is possible.


this in an arrow => function captures the value of this from the declaring scope. In this case, that's probably going to be window.

If you use the function keyword, however, then this is assigned based on how the function gets called (what comes before the . in obj.method()`).

For this reason, you should almost always use the function keyword to create a function that will be on a prototype.

(window as any).Number.prototype._toString = Number.prototype.toString;
(window as any).Number.prototype.toString = function (radix: number) {
    let val = this._toString.call(this, radix);
    console.log("value: "   val   ", Radix: "   radix)
    return val;
}

const a = 1
a.toString(16) // "value: 1, Radix: 16" 

CodePudding user response:

this in the arrow function is not the number. Use a function expression and put the original Number.prototype.toString in a variable and use that.

const original = Number.prototype.toString;
Number.prototype.toString = function toString(radix) {
    let val = original.call(this, radix);
    console.log({val, radix});
    return val;
}

CodePudding user response:

If you want to assign the old value of Number.prototype.toString to Number.prototype._toString, then you have to use declaration merging:

interface Number {
  _toString: Function;
}

Which allows you to do this:

Number.prototype._toString = Number.prototype.toString;

However, you may not want to make this function public. If you want to hide it and make it available only to your toString override, then use an IIFE. Also, don't use arrow functions as they capture this where they are declared instead of where they execute.

(function () {
  const originalToString = Number.prototype.toString;
  Number.prototype.toString = function (radix: number) {
    const val = originalToString.call(this, radix);
    console.log("value: "   val   ", \"Radix: "   radix)
    return val;
  }
})();

TypeScript playground

  • Related