Quelle est la différence entre 'extend' et 'implements' dans TypeScript

Réponses:

155

Version courte

  • extends veux dire:

La nouvelle classe est un enfant . Il tire des avantages de l'héritage. Il a toutes les propriétés, méthodes comme parent. Il peut remplacer certains d'entre eux et en implémenter de nouveaux, mais les éléments parents sont déjà inclus.

  • implements veux dire:

La nouvelle classe peut être traitée comme la même "forme" , alors qu'elle n'est pas un enfant . Il peut être passé à n'importe quelle méthode où le Personest requis, indépendamment du fait d'avoir un parent différent dePerson

Plus ...

En POO (langages comme C #, Java), nous utiliserions

extendspour profiter de l'héritage (voir wiki ). Petite cite:

... L'héritage dans la plupart des langages orientés objet basés sur des classes est un mécanisme dans lequel un objet acquiert toutes les propriétés et tous les comportements de l'objet parent. L'héritage permet aux programmeurs de: créer des classes basées sur des classes existantes ...

implementssera plus pour le polymorphisme (voir wiki ). Petite cite:

... le polymorphisme est la fourniture d'une interface unique à des entités de types différents ...

Ainsi, nous pouvons avoir un arbre d'héritage vraiment différent de notre class Man.

class Man extends Human ...

mais si nous déclarons également que nous pouvons prétendre être d'un type différent - Person:

class Man extends Human 
          implements Person ...

.. alors nous pouvons l'utiliser n'importe où, là où cela Personest nécessaire. Nous devons juste remplir les conditions des personnes "interface" (c'est-à-dire mettre en œuvre toutes ses activités publiques) .

implementautre classe? C'est vraiment cool

Le joli visage de Javascript (l'un des avantages) est le support intégré de la saisie Duck ( voir wiki ). Petite cite:

"Si ça marche comme un canard et ça caque comme un canard, alors ce doit être un canard."

Donc, en Javascript, si deux objets différents ... auraient une méthode similaire (par exemple render()) ils peuvent être passés à une fonction qui l'attend:

function(engine){
  engine.render() // any type implementing render() can be passed
}

Pour ne pas perdre cela - nous pouvons faire de même dans Typescript - avec un support plus typé. Et c'est là que

class implements class

a son rôle, là où ça a du sens

Dans les langues POO comme C#... pas moyen de faire ça ...

La documentation devrait également aider ici:

Interfaces étendant les classes

Lorsqu'un type d'interface étend un type de classe, il hérite des membres de la classe mais pas de leurs implémentations. C'est comme si l'interface avait déclaré tous les membres de la classe sans fournir d'implémentation. Les interfaces héritent même des membres privés et protégés d'une classe de base. Cela signifie que lorsque vous créez une interface qui étend une classe avec des membres privés ou protégés, ce type d'interface ne peut être implémenté que par cette classe ou une sous-classe de celle-ci.

Cela est utile lorsque vous avez une grande hiérarchie d'héritage, mais que vous souhaitez spécifier que votre code fonctionne uniquement avec les sous-classes qui ont certaines propriétés. Les sous-classes n'ont pas besoin d'être liées en plus d'hériter de la classe de base. Par exemple:

class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() { }
}

class TextBox extends Control {
    select() { }
}

// Error: Property 'state' is missing in type 'Image'.
class Image implements SelectableControl {
    private state: any;
    select() { }
}

class Location {

}

Donc pendant

  • extends signifie - il obtient tout de son parent
  • implementsdans ce cas, c'est presque comme implémenter une interface. L'objet enfant peut prétendre qu'il est parent ... mais il n'obtient aucune implémentation
Radim Köhler
la source
quand vous dites " extends-il obtient tout de son parent", cela s'applique-t-il aux membres privés? Par exemple n'avoir le nom de la propriété? class Person {private name: string} class man extends Person{gender: string;}man
davejoem
Les privés sont là aussi. Juste inaccessible par TS. Rendez-les protégés et vous pouvez les utiliser. Dans le cas des "outils", seule la partie publique a du sens. J'espère que ça aide un peu
Radim Köhler
Excellente réponse. Juste pas sûr par votre commentaire pour "privé est là mais pas accessible par TS". Voulez-vous dire que les propriétés privées sont copiées dans cet objet enfant nouvellement créé? Et dans le cas des outils, seules les propriétés publiques sont copiées?
kushalvm le
De plus, j'ai contourné un autre point. Si c'est la définition de extend. Alors s'il vous plaît si vous pouviez expliquer ce stackoverflow.com/questions/60390454
...
99

En typographie (et dans certains autres langages OO), vous avez des classes et des interfaces.

Une interface n'a pas d'implémentation, c'est juste un "contrat" ​​des membres / méthodes de ce type.
Par exemple:

interface Point {
    x: number;
    y: number;
    distance(other: Point): number;
}

Les instances qui implémentent cette Pointinterface doivent avoir deux membres de type number: xand y, et une méthode distancequi reçoit une autre Pointinstance et renvoie un number.
L'interface n'implémente aucun de ceux-ci.

Les classes sont les implémentations:

class PointImplementation implements Point {
    public x: number;
    public y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    public distance(other: Point): number {
        return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2));
    }
}

( code dans la cour de récréation )

Dans votre exemple, vous traitez votre Personclasse une fois comme une classe lorsque vous l'étendez et une fois comme une interface lorsque vous l'implémentez.
Votre code:

class Person {
    name: string;
    age: number;
}
class Child  extends Person {}

class Man implements Person {}

A une erreur de compilation disant:

La classe 'Man' implémente incorrectement l'interface 'Person'.
La propriété «nom» est manquante dans le type «Homme».

Et c'est parce que les interfaces manquent d'implémentation.
Donc, si vous avez implementune classe, vous ne prenez que son "contrat" ​​sans l'implémentation, vous devrez donc faire ceci:

class NoErrorMan implements Person {
    name: string;
    age: number;
}

( code dans la cour de récréation )

En fin de compte, dans la plupart des cas, vous voulez une extendautre classe et non pas à implementelle.

Nitzan Tomer
la source
6

Excellente réponse de @ nitzan-tomer! M'a beaucoup aidé ... J'ai prolongé un peu sa démo avec:

IPoint interface;
Point implements IPoint;
Point3D extends Point;

Et comment ils se comportent dans les fonctions qui attendent un IPointtype.

Donc, ce que j'ai appris jusqu'à présent et que j'ai utilisé comme règle empirique: si vous utilisez des classes et des méthodes qui attendent des types génériques, utilisez des interfaces comme types attendus. Et assurez-vous que le parent ou la classe de base utilise cette interface. De cette façon, vous pouvez utiliser toutes les sous-classes de celles-ci dans la mesure où elles implémentent l'interface.

Voici la démo étendue

andzep
la source
Cela ne répond pas à la question. Pour critiquer ou demander des éclaircissements à un auteur, laissez un commentaire sous sa publication. - De l'avis
aronisstav
1
@aronisstav Je n'ai posté qu'une démo étendue de ce que j'ai trouvé une bonne réponse qui m'a déjà aidé. Mais peut-être que quelqu'un d'autre trouverait le travail que j'ai fait pour prolonger la démo utile. C'est tout. Les commentaires ne sont pas vraiment destinés à mettre un bloc de code, c'est pourquoi je le trouve plus compréhensible dans une réponse-post. Alors quel est le problème avec ça?
andzep
Votre réponse a été (automatiquement?) Signalée en raison de sa longueur et de son contenu, est apparue dans ma file d'attente d'examen et j'ai donné du mérite aux raisons présentées dans l'indicateur. Sa principale contribution (expliquant que vous avez prolongé la démo) serait meilleure en commentaire. Avec le paragraphe ajouté, il est peut-être plus utile.
aronisstav
@andzep, votre exemple de démonstration étendu est vraiment utile.
namit
3
  1. L'interface étend l'interface avec la forme
  2. L'interface étend la classe avec la forme
  3. L'interface d'implémentation de classe doit implémenter tous les champs fournis par l'interface
  4. La classe implémente la classe avec la forme
  5. La classe étend la classe avec tous les champs

extendsse concentrer sur l'héritage et se implementsconcentrer sur la contrainte, qu'il s'agisse d'interfaces ou de classes.

lei li
la source
0

Étend les outils VS

  • extends: La classe enfant (qui est étendue) héritera de toutes les propriétés et méthodes de la classe est étend
  • implements: La classe qui utilise le implementsmot - clé devra implémenter toutes les propriétés et méthodes de la classe qu'elleimplements

En termes plus simples:

  • extends: Ici, vous obtenez toutes ces méthodes / propriétés de la classe parente, vous n'avez donc pas à l'implémenter vous-même
  • implements: Voici un contrat que la classe doit suivre. La classe doit implémenter au moins les méthodes / propriétés suivantes

Exemple:

class Person {
  name: string;
  age: number;

  walk(): void {
    console.log('Walking (person Class)')
  }

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
class child extends Person { }

// Man has to implements at least all the properties
// and methods of the Person class
class man implements Person {
  name: string;
  age: number

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  walk(): void {
    console.log('Walking (man class)')
  }

}

(new child('Mike', 12)).walk();
// logs: Walking(person Class)

(new man('Tom', 12)).walk();
// logs: Walking(man class)

Dans l'exemple, nous pouvons observer que la classe enfant hérite de tout de Person alors que la classe man doit tout implémenter de Person elle-même.

Si nous supprimions quelque chose de la classe man, par exemple la méthode de marche, nous obtiendrions l' erreur de compilation suivante :

La classe 'man' implémente incorrectement la classe 'Person'. Vouliez-vous étendre «Personne» et hériter de ses membres en tant que sous-classe? La propriété 'walk' est manquante dans le type 'man' mais obligatoire dans le type 'Person'. (2720)

Willem van der Veen
la source