web-dev-qa-db-fra.com

Extension de Object.prototype avec TypeScript

Je travaille actuellement sur une API TypeScript, qui nécessite certaines fonctionnalités supplémentaires liées au prototype Object (object.prototype).

Considérons le code suivant:

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

Vous voudrez peut-être essayer ceci directement au Aire de jeu .

Comme vous pouvez le constater, j'ai une classe appelée Foo (et non le nom d'objet que j'utiliserai). J'ai également étendu l'interface Object pour inclure deux nouvelles fonctions. Enfin, j'ai implémenté les fonctions sur la prototype (celles-ci fonctionnent en JavaScript pur, c'est juste TypeScript qui s'en plaint).

Où j'ai annoté "// c'est problématique ..." TypeScript le met en surbrillance en rouge, et affiche l'erreur suivante:

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

S’il s’agit d’un bogue TypeScript (je sais qu’il en est encore à la phase de développement, il faut donc résoudre beaucoup de bugs, et j’en ai déjà illustré quelques-uns sur CodePlex), ou bien il me manque quelque chose.

Pourquoi ai-je ce problème?

Si ce n'est pas un bogue TypeScript, comment puis-je résoudre ce problème?

25
series0ne

Ce bug est corrigé dans TS 0.9.0 alpha comme vous pouvez le voir ci-dessous: no error in Ts 0.9.0 alpha

Le terrain de jeu fonctionne toujours 0.8.3. 

Cela se produit essentiellement parce que les méthodes de certaines interfaces clés (Object, Number, String), etc. sont mises en cache en tant qu'optimisation des performances. 

Si vous courez ça. Lors du premier chargement, vous ne verrez pas cette erreur. Essayez

Dès que vous modifiez ce code, l'analyseur l'exécute à nouveau. Depuis qu'il a mis en cache l'ancienne définition d'interface, une définition de fonction dupliquée apparaît et est ensuite agrandie. Plus vous apportez de modifications à ce fichier, plus l'instruction d'erreur deviendra compliquée. 

10
basarat

J'avais:

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

pour que ce code soit compilé avec TypeScript, j'ai ajouté la ligne:

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

Merci basarat !

15
Tono Nam

J’ai étendu le tableau de la même manière et j’ai fait face à un gros problème quand une partie utilisait for i in ... pour le parcourir en boucle. Maintenant, vous ne pouvez pas contrôler tous les codes tiers et ces bugs peuvent devenir vraiment ennuyeux, alors je suggère un meilleur 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];
}
});

Maintenant, en utilisant Object.defineProperty, votre nouvelle propriété ne sera pas énumérée et elle est sûre. Le code ci-dessus donne à peu près un élément aléatoire du tableau. J'en ai fait un autre aussi qui fait apparaître un élément aléatoire de 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;
}
});

avec Object.defineProperty Vous obtenez plus de contrôle sur cette création et vous pouvez également ajouter des restrictions supplémentaires. 

2
Arijoon