Javascript 用TypeScript扩展Object.prototype
我目前正在开发一个TypeScript API,它需要绑定到对象原型(Object.prototype)的一些附加功能 考虑以下代码:Javascript 用TypeScript扩展Object.prototype,javascript,object,interface,prototype,typescript,Javascript,Object,Interface,Prototype,Typescript,我目前正在开发一个TypeScript API,它需要绑定到对象原型(Object.prototype)的一些附加功能 考虑以下代码: class Foo { } interface Object { GetFoo(): Foo; GetFooAsString(): string; } //This is problematic... Object.prototype.GetFoo = function() { return new Foo(); // No
class Foo {
}
interface Object {
GetFoo(): Foo;
GetFooAsString(): string;
}
//This is problematic...
Object.prototype.GetFoo = function() {
return new Foo();
// Note, this line is just for testing...I don't want my function to just return a blank instance of Foo!
}
//This is ok.
Object.prototype.GetFooAsString = function () {
return this.GetFoo().toString();
}
你可能想直接在办公室试试这个
如您所见,我有一个名为Foo
(不是我将使用的实际对象名称)的类。我还扩展了对象
接口,以包括两个新功能。最后,我针对原型
实现了这些函数(这些函数在纯JavaScript中工作,只是TypeScript有问题)
在我注释“//这是有问题的…”的地方,TypeScript用红色波浪线突出显示,并显示以下错误:
Cannot convert '() => Foo' to '{ (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; }': Call signatures of types '() => Foo' and '{ (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; }' are incompatible
() => Foo
要么这只是一个TypeScript错误(我知道它仍处于开发阶段,所以很多错误需要解决,我已经在CodePlex上演示了其中的一些),要么我遗漏了一些东西
为什么我会遇到这个问题
如果不是TypeScript错误,我如何修复它?此错误在TS 0.9.0 alpha中修复,如下所示: 操场仍在以0.8.3的速度运行 这主要是因为一些关键接口(对象、数字、字符串)上的方法作为性能优化得到缓存 如果你运行这个。第一次加载时,您不会看到该错误 一旦您对代码进行编辑,解析器就会再次检查代码,因为它缓存了旧的接口定义,因此会看到重复的函数定义,然后有效地崩溃。对该文件所做的编辑越多,错误语句将变得越复杂 我以前有:
// See if an array contains an object
Array.prototype.contains = function (obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
为了使用typescript编译代码,我添加了以下行:
interface Array {
contains(obj: Object): boolean;
}
谢谢 我以同样的方式扩展了数组,当一方使用
for I in…
循环它时,我遇到了一个大问题。现在,您无法控制每一个第三方代码,这些bug可能会变得非常烦人,因此我建议您使用更好的方法:
interface Array<T> {
crandom(): T;
}
/** Retrieve a random element from the list */
Object.defineProperty(Array.prototype, 'crandom', { value: function() {
let index = Math.floor(Math.random() * this.length);
return this[index];
}
});
使用
Object.defineProperty
可以更好地控制此创建,还可以添加其他限制 好极了!很高兴这不是因为糟糕的编码……至少不是因为我;-)不包含(obj:any):布尔值;在这里更合适吗?注意:我必须在这里使用接口数组
,否则我会得到“错误TS2428:接口的所有声明必须具有相同的类型参数”。如何使用导入
?正是这样。它允许您控制它的枚举和不变性,但是社区不赞成在现有对象(如数组、字符串、数字等)上添加或覆盖功能。您可能会发现,当使用defineProperty和writable:false时,您的代码可以正常工作,因为第三方代码无法覆盖您的代码。好的一点,我不同意人们不赞成它,因为在功能应该存在但不存在的情况下,扩展基类可能非常好(例如数组上的随机方法)。只要您编写的库不是供他人使用的,我个人认为扩展库没有问题,因为它的使用是适度的,不会过度使用。当ECMAScript委员会批准在这些对象上实现新功能的标准时会发生什么,但是你已经用相同的名字和不同的行为添加了你自己的功能?你的库突然死亡,因为它不兼容。PrototypeJS就是一个著名的例子,这正是为什么我提到用这种方式创建库不好的原因,我用前缀命名我的方法,比如crandom
,而不是random
,只是不要在任何需要加密强大的随机性或重要资源的上下文中使用Math.random()(如真钱)处于危险之中。Math.random()
可被利用,且加密性不强。请参阅。在在线洗牌游戏中使用此选项将是一个坏主意,或者在任何情况下,攻击者可能会利用预测下一个值的能力来实现不公平或恶意的结果。
Object.defineProperty(Array.prototype, 'popRandom', { value: function() {
let index = Math.floor(Math.random() * this.length);
let result = this[index];
this.splice(index, 1);
return result;
}
});