Before I proceed with my question, allow me to point out that I have already done some considerable research into this topic, and have already asked a couple of related questions, which you can find here:
Extending Object.prototype with TypeScript
Extending instance/static functions on existing prototypes with TypeScript
Whilst TypeScript seems to be maturing quite well along it's road to version 1.0, I'd noticed quite early on, in it's infancy that it was not easy to polyfill/shim/monkey patch/extend the functionality of core objects (Object, String, Number, Boolean etc) using TypeScript...however this is perfectly legal in pure JavaScript, and in my opinion, necessary for creating cross browser compatible and compliant APIs.
Now that we are on version 0.9.5 I've noticed much improvement in this area, and we can now extend the prototype of core objects, and it would seem that we can also add static functions to core objects too...HOWEVER...this appears to be buggy!
Consider the following code example:
interface Object {
/********************************/
/* Static functions */
/********************************/
// ECMAScript 6 Object.is function
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
is(v1: any, v2: any): boolean;
/********************************/
/* Prototype functions */
/********************************/
// Custom method for testing obejct equality (based on Java / C# principles)
equals(obj: any): boolean;
}
// Object.is polyfill
(() => {
if(!Object.is) {
Object.is = function(v1: any, v2: any): boolean {
if (v1 === 0 && v2 === 0) {
return 1 / v1 === 1 / v2;
}
if (v1 !== v1) {
return v2 !== v2;
}
return v1 === v2;
}
}
})();
// Object.prototype.equals implementation
Object.prototype.equals = function(obj: any): boolean {
return Object.is(obj, this);
}
Wanna play with it?...Playground
You've probably already noticed what's wrong here...interfaces shouldn't contain definitions for static functions, only those which should be bound to the prototype. In this respect, if you check out lib.d.ts, you will see that static functions are declared differently:
declare var Object: {
new (value?: any): Object;
(): any;
(value: any): any;
prototype: Object;
getPrototypeOf(o: any): any;
getOwnPropertyDescriptor(o: any, p: string): PropertyDescriptor;
getOwnPropertyNames(o: any): string[];
create(o: any, properties?: PropertyDescriptorMap): any;
defineProperty(o: any, p: string, attributes: PropertyDescriptor): any;
defineProperties(o: any, properties: PropertyDescriptorMap): any;
seal(o: any): any;
freeze(o: any): any;
preventExtensions(o: any): any;
isSealed(o: any): bool;
isFrozen(o: any): bool;
isExtensible(o: any): bool;
keys(o: any): string[];
}
So that means that we should really be adding is(v1: any, v2: any): boolean;
to the declaration...but declarations in TypeScript are not open-ended as are interfaces, therefore this is not possible.
That being said, if I remove the declaration from the interface, TypeScript then complains that Object.is
does not exist...so it would appear that I HAVE TO have it in there for the polyfill to work!
"Well if it works...kinda what's the problem?" - Yes it works, but only just and it's not elegant by any means.
Because is has been implemented statically, yet it is contracted as part of Object, TypeScript intellisense is still expecting Object.prototype.is
AND does not recognize the existence of Object.is
I feel like I'm waffling now so I'll get to the point.
- Is this a known issue?
- have I missed something?
- What is in the pipeline to rectify this issue?
NOTE: I've just noticed, it appears that you can overwrite declarations now, so you could add is(v1: any, v2: any): boolean;
to the declaration by overwriting it completely...but I still feel that this is not the most elegant solution.