在TypeScript中扩展本地JavaScript Number对象

8
根据TypeScript文档,扩展已有接口就像重新声明具有新属性,然后为其提供实现一样简单。我曾多次使用这种技术将静态方法扩展到本机JavaScript对象中。但是,对于成员函数,这种方法不起作用。
例如( TypeScript Playground链接):
interface Number {
  toPowerOf10: () => string;
}

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

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

上述代码可以成功编译,但在运行时会抛出以下异常:
Uncaught TypeError: _this.toExponential is not a function
罪魁祸首似乎是TypeScript为此场景生成JavaScript代码的方式:
var _this = this;
Number.prototype.toPowerOf10 = function () {
    return _this.toExponential();
};
var n = 1000;
alert(n.toPowerOf10());

很明显,这里的“_this”没有引用到“Number”实例。我不确定我是否做错了什么,或者在TypeScript中以这种方式扩展本地对象是否被支持。

1
非常有趣的问题!对我来说,使用function () {而不是(): string => {解决了这个问题,有人知道规范吗?这是期望的行为还是一个错误? - olydis
1
@olydis 使用箭头函数将捕获外部作用域,因此这是预期的行为。但是,如果您使用 implements Number 实现了自己的 Number 类,则使用箭头函数是可以的。在原型中分配一个函数是解决问题的方法。 - CodingIntrigue
顺便提一下,像这样将函数添加到原型中是不好的做法。它们可能会在未来被覆盖。 - CodingIntrigue
1个回答

25

你之所以出现问题是因为你使用箭头符号(=>)来声明新的函数,而不是function。虽然=>看起来好像是相同事物的简写,但它和function并不完全等效。特别地,=>将进行词法作用域,这意味着函数外部this将引用函数内部的this,它通过捕获编译后JavaScript中的本地_this实现。在这里,this是全局范围,因为你在那里声明了Number扩展。如果这是一个浏览器,this将指向window对象,该对象显然没有toExponential方法。

要实现你想要的功能,只需使用以下代码:

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

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

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

1
只是一个小提示:明确命名类型仍然是可能的(function(): string {)。 - olydis
此外,假设这是问题的实际表示方式,Number.prototype.toPowerOf10 = Number.prototype.toExponential; 将是等效的。 - CodingIntrigue
@JulianR 感谢。完美地解决了问题。我不知道 => 有稍微不同的含义。每天都能学到新东西。@RGraham 这只是为了在问题中节省空间而进行的简化 :) - Uzair Sajid
4
除非你在接口定义周围添加 declare global {,否则似乎无法编译。 - Ovidiu Dolha
全局范围的增强只能直接嵌套在外部模块或环境模块声明中。 - Nando

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接