interfaces injector injection injectable dependency cli interface angular inject

injector - interface angular cli



¿Es posible inyectar interfaz con angular2? (4)

La razón por la que no puede usar interfaces es porque una interfaz es un artefacto en tiempo de diseño de TypeScript. JavaScript no tiene interfaces. La interfaz de TypeScript desaparece del JavaScript generado. No hay información de tipo de interfaz para que Angular la encuentre en el tiempo de ejecución.

Solución 1:

La solución más sencilla es definir una clase abstracta que implemente la interfaz. A menudo, necesitas una clase abstracta de todos modos.

Interfaz:

import {Role} from "../../model/role"; export interface ProcessEngine { login(username: string, password: string):string; getRoles(): Role[]; }

Clase abstracta:

import {ProcessEngine} from "./process-engine.interface"; export abstract class ProcessEngineService implements ProcessEngine { abstract login(username: string, password: string): string; abstract getRoles(): Role[]; }

Clase concreta

import { Injectable } from ''@angular/core''; import {ProcessEngineService} from "./process-engine.service"; @Injectable() export class WebRatioEngineService extends ProcessEngineService { login(username: string, password: string) : string {...} getRoles(): Role[] {...} }

Ahora puedes definir a tu proveedor como de costumbre:

@NgModule({ ... providers: [ ..., {provide: ProcessEngineService, useClass: WebRatioEngineService} ] })

Solución 2:

La documentación oficial de Angular sugiere usar InjectionToken , similar a OpaqueToken. Aquí está el ejemplo:

Su interfaz y clase:

export interface AppConfig { apiEndpoint: string; title: string; } export const HERO_DI_CONFIG: AppConfig = { apiEndpoint: ''api.heroes.com'', title: ''Dependency Injection'' };

Define tu Token:

import { InjectionToken } from ''@angular/core''; export let APP_CONFIG = new InjectionToken<AppConfig>(''app.config'');

Registre el proveedor de dependencia usando el objeto InjectionToken, por ejemplo, en su app.module.ts:

providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }]

A continuación, puede inyectar el objeto de configuración en cualquier constructor que lo necesite, con la ayuda de un decorador @Inject:

constructor(@Inject(APP_CONFIG) config: AppConfig) { this.title = config.title; }

Me pregunto si hay una forma adecuada de inyectar interfaces en Angular2. (ver abajo)

Creo que esto está relacionado con el decorador faltante @Injectable () en la interfaz, pero parece que esto no está permitido.

Saludos.

Cuando CoursesServiceInterface se implementa como una interfaz, el compilador de TypeScript se queja "CoursesServiceInterface no puede encontrar el nombre":

import {CoursesServiceInterface} from ''./CoursesService.interface''; import {CoursesService} from ''./CoursesService.service''; import {CoursesServiceMock} from ''./CoursesServiceMock.service''; bootstrap(AppComponent, [ ROUTER_PROVIDERS, GlobalService, provide(CoursesServiceInterface, { useClass: CoursesServiceMock }) ]);

pero con CoursesServiceInterface como una interfaz:

import {Injectable} from ''angular2/core''; import {Course} from ''./Course.class''; //@Injectable() export interface CoursesServiceInterface { getAllCourses(): Promise<Course[]>;//{ return null; }; getCourse(id: number): Promise<Course>;// { return null; }; remove(id: number): Promise<{}>;// { return null; }; }

Cuando el servicio es una clase, el compilador de TypeScript ya no se queja:

import {Injectable} from ''angular2/core''; import {Course} from ''./Course.class''; @Injectable() export class CoursesServiceInterface { getAllCourses() : Promise<Course[]> { return null; }; getCourse(id: number) :Promise<Course> { return null; }; remove (id: number) : Promise<{}> { return null; }; }


Mi experiencia (proveniente del desarrollo de back-end de Java) en el desarrollo frontend es la siguiente.

Si hablamos de ''interfaz'', tengo la firme expectativa de que un principio fundamental de uso de la interfaz está asegurado por los idiomas que ofrecen la interfaz ''ofrecer''. Que es: ''código contra interfaz no contra implementación''.

Esto parece no estar asegurado por mecanografiado / angular2. (de lo que no deberían usar la interfaz de palabras, quizás).

Cuál fue mi caso (advertencia: estoy aprendiendo angular2, por lo que mi solución podría parecer fea para los usuarios avanzados):
El componente A1 tiene un componente hijo B.
El componente B debe conocer al padre y llamar a un método en el padre.
Así que el componente B recibe al padre a través de DependencyInjection en su constructor.

constructor( private a: A1Component) {}

Todo esta bien.
Que las cosas se compliquen.
Otro componente A2 puede ser el padre de comp. SEGUNDO.
Idealmente, debería inyectar en B una interfaz (no implementación) que sea implementada por A1 y A2 (esto sería naturalmente en el mundo Java).
Que B trabajaría con esta interfaz. Si es necesario, un encasillado a A2, por ejemplo, avisaría a B si la instancia que tiene es realmente A2 o no.

Hablo sobre componentes / clases simples, no servicios (veo que la mayoría de las soluciones se refieren a servicios).
Intenté usar @Host (), @Injectable (), OpaqueToken, proveedores, pero siempre hubo un error. Cuando al final pareció funcionar: en realidad, el objeto inyectado en el Componente B era un objeto vacío, no el principal, tal vez usé erróneamente a los proveedores y se creó un nuevo objeto vacío en lugar de inyectar el objeto principal.

Lo que hice al final : no usé interfaz.
Creé una clase base simple para A1 y A2, llamémosla ABase.
El componente B mantendría una referencia a esta clase base. La referencia se establecería en el constructor como este:

//BComponent: parent: ABase; constructor(@Optional parentA1: A1Component, @Optional parentA2: A2Component) { if( parentA1 ) this.parent = parentA1; else this.parent = parentA2 }

Sí, es una solución extraña, no agradable (viene del pensamiento del mundo Java, estoy de acuerdo), pero me quedé sin tiempo y me decepcionó la cosa de la "interfaz".

Actualizado

Reconsideré la respuesta anterior (es un mal diseño, feo ... fue en mis inicios con angular)

Ahora la documentación de Angular tiene una descripción clara sobre este problema exacto: encontrar el padre de un componente.

No se puede utilizar la interfaz, ya que la interfaz no se puede inyectar.

"Buscar componentes que implementen una interfaz sería mejor. Eso no es posible porque las interfaces de TypeScript desaparecen del JavaScript transpilado, que no es compatible con las interfaces. No hay ningún artefacto que buscar".

Tampoco se puede usar la clase base de posibles padres ... (esta es la causa raíz de mi respuesta anterior desesperada, mala)

¿Que funciona? Técnica: encontrar un padre por su interfaz de clase .

Principalmente:

El hijo B ve a un padre general padre (puede ser A1Component o A2Component)

export class BComponent { name = ''B''; constructor( @Optional() public parent: Parent ) { } }

Y cada componente principal posible proporciona un elemento principal (¡a nivel de componente!) Utilizando class-interface :

providers: [{ provide: Parent, useExisting: forwardRef(() => A1Component) }],


No, las interfaces no son compatibles con DI. Con las interfaces TypeScript ya no están disponibles en tiempo de ejecución, solo de forma estática y, por lo tanto, no se pueden utilizar como tokens DI.

Alternativamente, puede utilizar cadenas como claves o InjectionToken

provide(''CoursesServiceInterface'', {useClass: CoursesServiceMock}) // old

providers: [{provide: ''CoursesServiceInterface'', useClass: CoursesServiceMock}]

e inyectarlo como

constructor(@Inject(''CoursesServiceInterface'') private coursesService:CoursesServiceInterface) {}

Consulte también https://angular.io/api/core/InjectionToken


Use OpaqueToken, las interfaces no son compatibles con DI, ya que el propio Javascript no tiene interfaces. Una forma de hacer esto en Angular 2 es usando OpaqueToken. https://angular.io/docs/ts/latest/guide/dependency-injection.html

import { OpaqueToken } from ''@angular/core''; export let APP_CONFIG = new OpaqueToken(''app.config''); providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }] constructor(@Inject(APP_CONFIG) config: AppConfig) { this.title = config.title; }

Espero que esto pueda ayudar.