Mon expérience (venant du développement backend java) dans le développement frontend est la suivante.
Si nous parlons d'"interface", j'ai la ferme conviction qu'un principe fondamental de l'utilisation de l'interface est garanti par les langages qui "offrent" une interface. Ce principe est le suivant : "codez contre l'interface et non contre l'implémentation".
Cela semble ne pas être assuré par typescript/angular2. (qu'ils ne devraient pas encore utiliser l'interface word, peut-être).
Quel était mon cas (avertissement : Je suis en train d'apprendre angular2, donc ma solution de contournement pourrait sembler laide aux utilisateurs avancés) :
Le composant A1 a un composant enfant B.
Le composant B doit connaître le parent et appeler une méthode sur le parent.
Ainsi, le composant B reçoit le parent via l'injection de dépendance dans son constructeur.
constructor( private a: A1Component) {}
Tout va bien.
Ensuite, les choses se compliquent.
Un autre composant A2 peut être le parent de comp. B.
Idéalement, je devrais injecter dans B une interface (pas une implémentation) qui est implémentée à la fois par A1 et A2 (ce qui serait naturel dans le monde Java).
Alors que B fonctionnerait avec cette interface. Si nécessaire, un typecast vers A2, par exemple, permettrait à B de savoir si l'instance qu'il possède est réellement A2 ou non.
Je parle de simples composants/classes, pas de services (je vois que la plupart des solutions font référence à des services).
J'ai essayé d'utiliser @Host(), @Injectable(), OpaqueToken, Providers mais il y avait toujours une erreur. Mais à la fin, cela semble fonctionner : en réalité, l'objet injecté dans le composant B était un objet vide, et non le parent - peut-être ai-je mal utilisé les providers et un nouvel objet vide a été créé au lieu d'injecter l'objet parent.
Ce que j'ai fait à la fin : Je n'ai pas utilisé d'interface.
J'ai créé une classe de base simple pour A1 et A2 - appelons-la ABase.
Le composant B conserverait une référence à cette classe de base. La référence sera définie dans le constructeur comme ceci :
//BComponent:
parent: ABase;
constructor(@Optional parentA1: A1Component, @Optional parentA2: A2Component) {
if( parentA1 )
this.parent = parentA1;
else
this.parent = parentA2
}
Oui, c'est une solution de contournement étrange, pas très agréable (venant du monde Java, je suis d'accord) - mais je n'ai pas eu le temps et j'ai été déçu par l'aspect "interface".
Mise à jour de
Je reconsidère la réponse précédente (c'est mauvais design, laid ... était à mes débuts avec angular)
La documentation d'Angular contient désormais une description claire de ce problème précis : trouver le parent d'un composant.
Impossible d'utiliser l'interface - car l'interface ne peut pas être injectée.
"Rechercher des composants qui implémentent une interface serait mieux. Ce n'est pas possible car les interfaces TypeScript disparaissent du JavaScript transposé, qui ne prend pas en charge les interfaces. Il n'y a pas d'artefact à rechercher."
Ne peut pas utiliser classe de base des parents possibles ni l'un ni l'autre ... (c'est la cause profonde de ma précédente réponse désespérée et mauvaise).
Qu'est-ce qui fonctionne ? La technique : trouver un parent par son interface de classe .
Principalement :
L'enfant B voit un parent général Parent
(peut être A1Component ou A2Component)
export class BComponent {
name = 'B';
constructor( @Optional() public parent: Parent ) { }
}
Et chaque composant parent possible fournit un Parent
(au niveau des composants ! !!) en utilisant classe-interface :
providers: [{ provide: Parent, useExisting: forwardRef(() => A1Component) }],