Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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).

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.

As you can see, I have a class called Foo (not the actual object name I will be using). I have also extended the Object interface to include two new functions. Finally I have implemented the functions against the prototype (these work in pure JavaScript, it's just TypeScript that complains).

Where I have annotated "//this is problematic..." TypeScript highlights this with a red squiggly, and shows the following error:

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.

Why am I getting this issue?

If it's not a TypeScript bug, how can I fix this?

like image 220
Matthew Layton Avatar asked May 29 '13 11:05

Matthew Layton


People also ask

Should works by extending object prototype?

The short answer is Yes, you should do it.

How do you use a prototype in TypeScript?

Prototype is a creational design pattern that allows cloning objects, even complex ones, without coupling to their specific classes. All prototype classes should have a common interface that makes it possible to copy objects even if their concrete classes are unknown.

How does prototypal inheritance work?

The Prototypal Inheritance is a feature in javascript used to add methods and properties in objects. It is a method by which an object can inherit the properties and methods of another object. Traditionally, in order to get and set the [[Prototype]] of an object, we use Object. getPrototypeOf and Object.


2 Answers

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:

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

Thanks basarat!

like image 145
Tono Nam Avatar answered Sep 21 '22 15:09

Tono Nam


This bug is fixed in TS 0.9.0 alpha as you can see below: no error in Ts 0.9.0 alpha

The playground is still running 0.8.3.

This basically happens because methods on some key interfaces ( Object, Number, String ) etc get cached as a performance optimization.

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.

like image 42
basarat Avatar answered Sep 23 '22 15:09

basarat