此答案适用于 TypeScript 1.8+。这类问题还有很多其他答案,但它们似乎都涵盖了旧版本。
在 TypeScript 中扩展原型有两个部分。
第 1 部分 - 声明
声明新成员以便它可以通过类型检查。您需要声明一个与要修改的构造函数/类同名的接口,并将其放在正确声明的命名空间/模块下。这称为范围扩充。
以这种方式扩展模块只能在特殊声明.d.tsfiles*中完成。
//in a .d.ts file:
declare global {
interface String {
padZero(length : number) : string;
}
}
外部模块中的类型名称包含引号,例如"bluebird"。
Array<T> 和String 等全局类型的模块名称为global,不带任何引号。但是,在许多 TypeScript 版本中,您可以完全放弃模块声明并直接声明接口,以具有如下内容:
declare interface String {
padZero(length : number) : string;
}
在 1.8 之前的某些版本和 2.0 之后的某些版本中就是这种情况,例如最新版本 2.5。
请注意,.d.ts 文件中不能有除declare 语句之外的任何内容,否则将不起作用。
这些声明被添加到包的环境范围内,因此它们将应用于所有 TypeScript 文件,即使您从未直接 import 或 ///<reference 文件。但是,您仍然需要导入您在第 2 部分中编写的实现,如果您忘记执行此操作,则会遇到运行时错误。
* 从技术上讲,您可以克服此限制并将声明放入常规的 .ts 文件中,但这会导致编译器出现一些挑剔的行为,因此不建议这样做。
第 2 部分 - 实施
第 2 部分实际上是实现成员并将其添加到它应该存在的对象中,就像在 JavaScript 中所做的那样。
String.prototype.padZero = function (this : string, length: number) {
var s = this;
while (s.length < length) {
s = '0' + s;
}
return s;
};
注意几点:
-
String.prototype 而不仅仅是 String,这是 String 构造函数,而不是它的原型。
- 我使用显式的
function 而不是箭头函数,因为function 将正确地从调用它的位置接收this 参数。箭头函数将始终使用与声明它的位置相同的this。我们不希望发生这种情况的一次是在扩展原型时。
- 显式
this,因此编译器知道我们期望的this 的类型。此部分仅在 TS 2.0+ 中可用。如果您正在为 1.8- 编译,请删除 this 注释。如果没有注释,this 可能会被隐式键入 any。
导入 JavaScript
在 TypeScript 中,declare 构造将成员添加到环境范围,这意味着它们出现在所有文件中。为确保您在第 2 部分中的实现已连接,import 位于应用程序开头的文件。
您按如下方式导入文件:
import '/path/to/implementation/file';
无需导入任何东西。你也可以从文件中导入一些东西,但你不需要导入你在原型上定义的函数。