简体   繁体   English

使用TypeScript扩展Object.prototype

[英]Extending Object.prototype with TypeScript

I am currently working on a TypeScript API, which requires some additional features binding to the Object prototype (Object.prototype). 我目前正在开发TypeScript API,它需要一些绑定到Object原型(Object.prototype)的附加功能。

Consider the following code: 请考虑以下代码:

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();
}

You might want to try this directly at the Playground . 您可能想直接在Playground尝试这个。

As you can see, I have a class called Foo (not the actual object name I will be using). 如您所见,我有一个名为Foo的类(不是我将使用的实际对象名)。 I have also extended the Object interface to include two new functions. 我还扩展了Object接口以包含两个新函数。 Finally I have implemented the functions against the prototype (these work in pure JavaScript, it's just TypeScript that complains). 最后,我已经针对prototype实现了这些功能(这些功能在纯JavaScript中运行,只是抱怨的TypeScript)。

Where I have annotated " //this is problematic... " TypeScript highlights this with a red squiggly, and shows the following error: 我在其中注释“ //这是有问题的...... ”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

Either this is just a TypeScript bug (I know it's still in development phase, so a lot of the bugs need ironing out, and I have illustrated some of these on CodePlex already), or, I'm missing something. 要么这只是一个TypeScript错误(我知道它仍处于开发阶段,所以很多错误需要解决,我已经在CodePlex上说明了一些),或者,我遗漏了一些东西。

Why am I getting this issue? 为什么我会遇到这个问题?

If it's not a TypeScript bug, how can I fix this? 如果它不是TypeScript错误,我该如何解决这个问题?

I used to have: 我曾经有过:

// 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;
}

in order to make that code compile with typescript I added the line: 为了使用typescript编译代码,我添加了以下行:

interface Array {
    contains(obj: Object): boolean;
}

Thanks basarat ! 谢谢basarat

This bug is fixed in TS 0.9.0 alpha as you can see below: 这个错误在TS 0.9.0 alpha中修复,如下所示: Ts 0.9.0 alpha中没有错误

The playground is still running 0.8.3. 操场仍在运行0.8.3。

This basically happens because methods on some key interfaces ( Object, Number, String ) etc get cached as a performance optimization. 这基本上是因为某些关键接口(Object,Number,String)等上的方法被缓存为性能优化。

If you run this. 如果你运行这个。 The first time it loads you will not see that error. 第一次加载时您将看不到该错误。 Try It . 试试吧

As soon as you make an edit to that code, the parser goes through the code again, and since it cached the old interface definition sees a duplicate function definition and then effectively blows up. 一旦你对该代码进行编辑,解析器就会再次遍历代码,并且由于它缓存了旧的接口定义,因此会看到重复的函数定义,然后会有效地破坏。 The more edits you make to that file the more complicated the error statement will get. 您对该文件所做的编辑越多,错误语句就越复杂。

I have extended the Array the same way and faced a big problem when sa party was using for i in ... to loop over it. 我已经以相同的方式扩展了阵列,并且当一个派对正在使用for i in ...时候面对一个大问题for i in ...来循环它。 Now you can't control every third party code and these bugs could get really annoying so I suggest a better aprocach: 现在你无法控制每个第三方代码,这些错误可能真的很烦人,所以我建议一个更好的aprocach:

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];
}
});

Now by using Object.defineProperty your new property won't be enumerated over and it is safe. 现在通过使用Object.defineProperty您的新属性将不会被枚举,并且是安全的。 The above code pretty much gives a random element from the array. 上面的代码几乎给出了数组中的随机元素。 I made another one too which pops a random element from array: 我又做了一个从数组中弹出一个随机元素:

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;
}
});

with Object.defineProperty You get more control over this creation and you can add additional restrictions too. 使用Object.defineProperty您可以更好地控制此创建,也可以添加其他限制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM