web-dev-qa-db-fra.com

Existe-t-il un moyen de surcharger une méthode dans TypeScript?

Existe-t-il un moyen de surcharger une méthode en langage TypeScript?

Je veux réaliser quelque chose comme ça:

class TestClass {
    someMethod(stringParameter: string): void {
        alert("Variant #1: stringParameter = " + stringParameter);
    }

    someMethod(numberParameter: number, stringParameter: string): void {
        alert("Variant #2: numberParameter = " + numberParameter + ", stringParameter = " + stringParameter);
    }
}

var testClass = new TestClass();
testClass.someMethod("string for v#1");
testClass.someMethod(12345, "string for v#2");

Voici un exemple de ce que je ne veux pas faire (je déteste vraiment cette partie de la surcharge bidon dans JS):

class TestClass {
    private someMethod_Overload_string(stringParameter: string): void {
        // A lot of code could be here... I don't want to mix it with switch or if statement in general function
        alert("Variant #1: stringParameter = " + stringParameter);
    }

    private someMethod_Overload_number_string(numberParameter: number, stringParameter: string): void {
        alert("Variant #2: numberParameter = " + numberParameter + ", stringParameter = " + stringParameter);
    }

    private someMethod_Overload_string_number(stringParameter: string, numberParameter: number): void {
        alert("Variant #3: stringParameter = " + stringParameter + ", numberParameter = " + numberParameter);
    }

    public someMethod(stringParameter: string): void;
    public someMethod(numberParameter: number, stringParameter: string): void;
    public someMethod(stringParameter: string, numberParameter: number): void;

    public someMethod(): void {
        switch (arguments.length) {
        case 1:
            if(typeof arguments[0] == "string") {
                this.someMethod_Overload_string(arguments[0]);
                return;
            }
            return; // Unreachable area for this case, unnecessary return statement
        case 2:
            if ((typeof arguments[0] == "number") &&
                (typeof arguments[1] == "string")) {
                this.someMethod_Overload_number_string(arguments[0], arguments[1]);
            }
            else if ((typeof arguments[0] == "string") &&
                     (typeof arguments[1] == "number")) {
                this.someMethod_Overload_string_number(arguments[0], arguments[1]);
            }
            return; // Unreachable area for this case, unnecessary return statement
        }
    }
}


var testClass = new TestClass();
testClass.someMethod("string for v#1");
testClass.someMethod(12345, "string for v#2");
testClass.someMethod("string for v#3", 54321);
99
Void-995

Selon la spécification, TypeScript prend en charge la surcharge de méthodes, mais elle est assez maladroite et comprend de nombreux types de paramètres de contrôle de travail manuel. Je pense que c’est principalement parce que le plus proche de la surcharge de méthodes en JavaScript simple inclut cette vérification et TypeScript tente également de ne pas modifier le corps des méthodes afin d’éviter des coûts de performances d’exécution inutiles.

Si je le comprends bien, vous devez d’abord écrire une déclaration de méthode pour chacune des surcharges, puis une implémentation de méthode = qui vérifie ses arguments pour décider quelle surcharge a été appelée. La signature de l'implémentation doit être compatible avec toutes les surcharges.

class TestClass {
    someMethod(stringParameter: string): void;
    someMethod(numberParameter: number, stringParameter: string): void;

    someMethod(stringOrNumberParameter: any, stringParameter?: string): void {
        if (stringOrNumberParameter && typeof stringOrNumberParameter == "number")
            alert("Variant #2: numberParameter = " + stringOrNumberParameter + ", stringParameter = " + stringParameter);
        else
            alert("Variant #1: stringParameter = " + stringOrNumberParameter);
    }
}
141
svick

Mettre à jour pour plus de clarté. La surcharge de méthode dans TypeScript est une fonctionnalité utile dans la mesure où elle vous permet de créer des définitions de type pour les bibliothèques existantes avec une API devant être représentée.

Cependant, lors de l'écriture de votre propre code, vous pourrez peut-être éviter la surcharge cognitive des surcharges en utilisant des paramètres facultatifs ou par défaut. Il s’agit de l’alternative la plus lisible aux surcharges de méthodes et maintient également votre API en évitant de créer des surcharges avec des commandes non intuitives.

La loi générale des surcharges TypeScript est la suivante:

Si vous pouvez supprimer les signatures de surcharge et que tous vos tests réussissent, vous n’avez pas besoin de surcharges TypeScript

Vous pouvez généralement obtenir la même chose avec des paramètres facultatifs ou par défaut, avec des types d'union ou avec un peu d'orientation objet.

La question réelle

La question actuelle demande une surcharge de:

someMethod(stringParameter: string): void {

someMethod(numberParameter: number, stringParameter: string): void {

Désormais, même dans les langages prenant en charge les surcharges avec des implémentations distinctes (remarque: les surcharges TypeScript partagent une seule implémentation) - les programmeurs sont des conseils pour assurer la cohérence des commandes. Cela ferait les signatures:

someMethod(stringParameter: string): void {

someMethod(stringParameter: string, numberParameter: number): void {

Le stringParameter est toujours requis, il commence donc. Vous pourriez écrire ceci en tant que surcharge TypeScript de travail:

someMethod(stringParameter: string): void;
someMethod(stringParameter: string, numberParameter: number): void;
someMethod(stringParameter: string, numberParameter?: number): void {
    if (numberParameter != null) {
        // The number parameter is present...
    }
}

Mais suivant la loi des surcharges TypeScript, nous pouvons supprimer les signatures de surcharge et tous nos tests continueront à passer.

someMethod(stringParameter: string, numberParameter?: number): void {
    if (numberParameter != null) {
        // The number parameter is present...
    }
}

La question réelle, dans l'ordre réel

Si vous étiez déterminé à conserver l'ordre d'origine, les surcharges seraient les suivantes:

someMethod(stringParameter: string): void;
someMethod(numberParameter: number, stringParameter: string): void;
someMethod(a: string | number, b?: string | number): void {
  let stringParameter: string;
  let numberParameter: number;

  if (typeof a === 'string') {
    stringParameter = a;
  } else {
    numberParameter = a;

    if (typeof b === 'string') {
      stringParameter = b;
    }
  }
}

Maintenant, cela demande beaucoup de branches pour déterminer où mettre les paramètres, mais vous vouliez vraiment conserver cet ordre si vous lisiez si loin ... mais attendez, que se passera-t-il si nous appliquons la loi des surcharges TypeScript?

someMethod(a: string | number, b?: string | number): void {
  let stringParameter: string;
  let numberParameter: number;

  if (typeof a === 'string') {
    stringParameter = a;
  } else {
    numberParameter = a;

    if (typeof b === 'string') {
      stringParameter = b;
    }
  }
}

Déjà assez de ramifications

Bien sûr, étant donné la quantité de vérification de type que nous devons faire ... la meilleure réponse est peut-être simplement d’avoir deux méthodes:

someMethod(stringParameter: string): void {
  this.someOtherMethod(0, stringParameter);
}

someOtherMethod(numberParameter: number, stringParameter: string): void {
  //...
}
28
Fenton

Je souhaite que. Je veux aussi cette fonctionnalité, mais TypeScript doit être interopérable avec du JavaScript non typé qui ne contient pas de méthodes surchargées. Si votre méthode surchargée est appelée à partir de JavaScript, elle ne peut être répartie que vers une implémentation de méthode.

Il y a quelques discussions pertinentes sur codeplex. par exemple.

https://TypeScript.codeplex.com/workitem/617

Je pense toujours que TypeScript devrait générer tout le ifing et le switch afin que nous n’ayons pas besoin de le faire.

8
nicopolyptic

Javascript n'a aucun concept de surcharge. TypeScript n'est pas c # ou Java.

Mais vous pouvez implémenter la surcharge dans TypeScript.

Lire cet article http://www.gyanparkash.in/function-overloading-in-TypeScript/

2
Gyan

Pourquoi ne pas utiliser interface définie par propriété optionnelle comme argument de la fonction ..

Dans le cas de cette question, l'utilisation d'une interface en ligne définie avec certaines propriétés facultatives uniquement pourrait directement générer du code comme ci-dessous:

class TestClass {

    someMethod(arg: { stringParameter: string, numberParameter?: number }): void {
        let numberParameterMsg = "Variant #1:";
        if (arg.numberParameter) {
            numberParameterMsg = `Variant #2: numberParameter = ${arg.numberParameter},`;
        }
        alert(`${numberParameterMsg} stringParameter = ${arg.stringParameter}`);
    }
}

var testClass = new TestClass();
testClass.someMethod({ stringParameter: "string for v#1" });
testClass.someMethod({ numberParameter: 12345, stringParameter: "string for v#2" });

La surcharge fournie dans TypeScript étant, comme mentionné dans les commentaires d'autres personnes, une liste des différentes signatures de fonctions sans prendre en charge les codes d'implémentation correspondants, comme d'autres langages statiques. L'implémentation doit donc toujours être effectuée dans un seul corps de fonction, ce qui rend l'utilisation de la surcharge de fonctions dans TypeScript moins confortable que les langages prenant en charge la fonctionnalité de surcharge réelle.

Cependant, de nombreux éléments nouveaux et pratiques fournis dans TypeScript ne sont pas disponibles dans le langage de programmation hérité, où la prise en charge de propriétés facultatives dans une interface anonyme est une telle approche pour répondre à la zone confortable de la surcharge de fonctions héritées, je pense.

1
千木郷