web-dev-qa-db-fra.com

Étendre ou implémenter une classe abstraite pure dans TypeScript

Supposons que j'ai une classe abstraite pure (c'est-à-dire une classe abstraite sans aucune implémentation):

abstract class A {
    abstract m(): void;
}

Comme en C # et Java, je peux étendre la classe abstraite:

class B extends A {
    m(): void { }
}

Mais contrairement à en C # et Java, je peux aussi implémenter la classe abstraite:

class C implements A {
    m(): void { }
}

Comment les classes B et C se comportent-elles différemment? Pourquoi choisirais-je l'un ou l'autre?

(Actuellement, les typesScript manuel et spécification du langage ne couvrent pas les classes abstraites.)

54
Michael Liu

Le mot clé implémente considère la classe A comme une interface, ce qui signifie que C doit implémenter toutes les méthodes définies dans A , peu importe qu’ils aient une implémentation ou non [~ # ~] a [~ # ~] . De plus, il n'y a pas d'appels aux super méthodes en [~ # ~] c [~ # ~] .

étend se comporte plutôt comme ce à quoi vous vous attendiez du mot-clé. Vous devez implémenter uniquement les méthodes abstraites et les super-appels sont disponibles/générés.

Je suppose que dans le cas des méthodes abstraites, cela ne fait aucune différence. Mais vous avez rarement une classe avec uniquement des méthodes abstraites. Si vous le faites, il serait beaucoup mieux de le transformer en interface .

Vous pouvez facilement voir cela en regardant le code généré. J'ai fait un exemple de terrain de jeu ici .

69
toskv

J'ai été conduit ici parce que je venais de me poser la même question et en lisant les réponses, il m'est apparu que le choix affecterait également l'opérateur instanceof.

Dans la mesure où une classe abstraite est une valeur réelle qui est émise vers JS, elle peut être utilisée pour les contrôles d’exécution lors de l’extension d’une sous-classe.

abstract class A {}

class B extends A {}

class C implements A {}

console.log(new B() instanceof A) // true
console.log(new C() instanceof A) // false
9
Tao

En s'appuyant sur @ toskv's answer , si vous étendez une classe abstraite, vous devez appeler super() dans le constructeur de la sous-classe. Si vous implémentez la classe abstraite, vous n'avez pas à appeler super() (mais vous devez implémenter toutes les méthodes déclarées dans la classe abstraite, y compris les méthodes privées).

Implémenter une classe abstraite au lieu de l'étendre pourrait être utile si vous souhaitez créer une classe fictive pour les tests sans avoir à vous soucier des dépendances et du constructeur de la classe d'origine.

7
Cory

Dans l'exemple d'étendues que vous donnez, vous n'ajoutez rien de nouveau à la classe. Donc, il est prolongé par rien. Bien que prolonger par rien ne soit valide TypeScript, il me semblerait que dans ce cas, "implémenter" serait plus approprié. Mais en fin de compte, ils sont équivalents.

0
Quentin 2