¿Cómo usar Dependency Injection (DI) correctamente en Angular2?

He estado tratando de descubrir cómo funciona la Inyección de Dependencia (DI) en Angular2. Me encontré con muchos problemas / problemas cada vez que intenté Inyectar un servicio / clase en mis componentes.

Desde diferentes artículos en Google, necesito usar providers: [] en la configuración del Componente, o algunas veces necesito usar @Inject() en mi constructor o inyectar directamente en el bootstrap(app, [service]) ? También he visto algunos artículos que me quieren poner @injectable decorator.

Por ejemplo: para inyectar Http, solo necesito import{Http} y poner Http en los proveedores, pero para FormBuilder, necesito usar @Inject() en el constructor.

¿Hay alguna regla de oro para cuándo usar qué? ¿Podría proporcionar algún fragmento de código de ejemplo? Gracias 🙂

    La dependency injection en Angular2 se basa en inyectores jerárquicos que están vinculados al árbol de componentes.

    Esto significa que puede configurar proveedores en diferentes niveles:

    • Para toda la aplicación cuando se inicia el proceso. En estos casos, todos los subinyectores (los componentes) verán este proveedor y compartirán la instancia asociada con. Al interactuar, será la misma instancia
    • Para un componente específico y sus subcomponentes. Igual que antes, pero para un componente específico. Otros componentes no verán a este proveedor. Si redefine algo definido anteriormente (cuando se realiza un arranque, por ejemplo), este proveedor se usará en su lugar. Entonces puedes anular las cosas.
    • Para servicios. No hay proveedores asociados con ellos. Usan los del inyector del elemento que dispara (directamente = un componente o indirectamente = un componente que desencadena la llamada de la cadena de servicio)

    En cuanto a tus otras preguntas:

    • @Injectable. Para inyectar en una clase, necesitas un decorador. Los componentes tienen uno (el @Component uno) pero los servicios son clases simples. Si un servicio requiere que se le inserten dependencias, necesita este decorador.
    • @Inyectar. En la mayoría de los casos, el tipo de parámetros del constructor es suficiente para permitir que Angular2 determine qué inyectar. En algunos casos (por ejemplo, si usa explícitamente un OpaqueToken y no una clase para registrar proveedores), debe especificar algunas sugerencias sobre qué inyectar. En tales casos, debe usar @Inject.

    Vea estas preguntas para detalles adicionales:

    • ¿Cuál es la mejor manera de inyectar un servicio en otro en angular 2 (Beta)?
    • Angular2: Inyectar una clase no @Injectable
    • Inyectar todos los servicios que implementan alguna interfaz

    Pregunta amplia, versión TL; DR


    @Injectable ()

    • es un decorador que le dice a la typescript que la clase decorada tiene dependencies y no quiere decir que esta clase pueda ser inyectada en otra.

    • Y luego TypeScript entiende que necesita Inyectar los metadatos necesarios en la clase decorada al construir, mediante el uso de las dependencias imported .

    bootstrap (aplicación, [servicio])

    • bootstrap () se encarga de crear un inyector raíz para nuestra aplicación cuando está bootstrap. Toma una lista de proveedores como segundo argumento que se pasará directamente al inyector cuando se cree.

    • Arranca su aplicación con los servicios que se usarán en muchos lugares como Http , lo que también significa que no necesitará escribir providers: [Http] en la configuración de su clase.

    proveedores: [servicio]

    • los proveedores también hacen el trabajo de pasar todos los argumentos de los servicios a Injector .

    • Pones servicios en proveedores si no es bootstrap() con ped. Y solo se necesita en algunos lugares.

    @Inyectar()

    • es también un decorador una función que hace el trabajo de inyectar realmente esos servicios
      Me gusta esto. constructor(@Inject(NameService) nameService)
    • pero si usa TS, todo lo que necesita hacer es que este constructor(nameService: NameService) y el typescript se encarguen del rest.

    Otras lecturas

    • Si quieres profundizar en DI , echa un vistazo a este increíble artículo

    • y para entender Decoradores vs Anotaciones, mira esto .

    • Aquí está la guía oficial .

    • Gunter's Answer Mark Rajcok's Answer y su Accepted Answer

    Espero que esto ayude. 🙂

    Necesito usar proveedores: []

    Para que la dependency injection pueda crear instancias para usted, necesita registrar proveedores para estas clases (u otros valores) en alguna parte .

    Donde registra un proveedor determina el scope del valor creado. Angulars DI es jerárquico.
    Si registra un proveedor en la raíz del árbol


    > = RC.5

     @NgModule({ providers: [/*providers*/] ... }) 

    o para módulos cargados perezosos

     static forRoot(config: UserServiceConfig): ModuleWithProviders { return { ngModule: CoreModule, providers: [ {provide: UserServiceConfig, useValue: config } ] }; } 

    < = RC.4

    ( bootstrap(AppComponent, [Providers}) o @Component(selector: 'app-component', providers: [Providers]) (componente raíz)


    luego, todos los componentes y servicios que solicitan una instancia obtienen la misma instancia.

    Si un proveedor está registrado en uno de los componentes secundarios, se proporciona una nueva instancia (diferente) para los descendientes de este componente.

    Si un componente solicita una instancia (mediante un parámetro de constructor), DI ve “hacia arriba” el árbol de componentes (comenzando desde la hoja hacia la raíz) y toma el primer proveedor que encuentra. Si ya se creó una instancia para este proveedor, esta instancia se usa, de lo contrario, se crea una nueva instancia.

    @Inyectar()

    Cuando un componente o servicio solicita un valor de DI como

     constructor(someField:SomeType) {} 

    DI busca el proveedor por el tipo SomeType . Si se @Inject(SomeType)

     constructor(@Inject(SomeType) someField:SomeType) {} 

    DI busca el proveedor por el parámetro pasado a @Inject() . En el ejemplo anterior, el parámetro pasado a @Inject() es el mismo que el tipo del parámetro, por @Inject(SomeType) tanto, @Inject(SomeType) es redundante.

    Sin embargo, hay situaciones en las que desea personalizar el comportamiento, por ejemplo, para inyectar una configuración.

     constructor(@Inject('someName') someField:string) {} 

    El tipo de string no es suficiente para distinguir una configuración específica cuando tiene varios registrados.
    El valor de configuración debe registrarse como proveedor en algún lugar como


    > = RC.5

     @NgModule({ providers: [{provide: 'someName', useValue: 'abcdefg'})] ... }) export class AppModule {} 

    < = RC.4

     bootstrap(AppComponent, [provide('someName', {useValue: 'abcdefg'})]) 

    Por lo tanto, no necesita @Inject() para FormBuilder si el constructor se parece a

     constructor(formBuilder: FormBuilder) {} 

    Agregaré algunas cosas que no vi mencionadas en las otras respuestas. (En el momento en que escribo esto, eso significa las respuestas de Thierry, Günter y A_Singh).

    • Siempre agregue Injectable() a los servicios que cree. Aunque solo es necesario si su servicio necesita inyectar algo, es una buena práctica incluirlo siempre.
    • La matriz de providers en directivas / componentes y la matriz de providers en NgModules son las únicas dos maneras de registrar proveedores que no están incorporados. (Los ejemplos de objetos incorporados que no tenemos que registrar son ElementRef , ApplicationRef , etc. Simplemente podemos inyectarlos).
    • Cuando un componente tiene una matriz de providers , ese componente recibe un inyector angular. Los inyectores son consultados cuando algo quiere inyectar una dependencia (como se especifica en el constructor). Me gusta pensar en el árbol de inyectores como un árbol de reserva que el árbol de componentes. El primer inyector que puede satisfacer una solicitud de dependencia lo hace. Esta jerarquía de inyectores permite que las dependencias sean únicas o no.

    ¿Por qué @Injectable ()?

    @Injectable () marca una clase como disponible para un inyector para creación de instancias. En términos generales, un inyector informará un error cuando intente crear una instancia de una clase que no esté marcada como @Injectable ().

    Da la casualidad de que podríamos haber omitido @Injectable () desde nuestra primera versión de HeroService porque no tenía parámetros inyectados. Pero debemos tenerlo ahora que nuestro servicio tiene una dependencia inyectada. Lo necesitamos porque Angular requiere metadatos de parámetros de constructor para inyectar un Logger.

    SUGERENCIA: AGREGAR @INJECTABLE () A CADA CLASE DE SERVICIO Recomendamos agregar @Injectable () a cada clase de servicio, incluso aquellas que no tienen dependencias y, por lo tanto, técnicamente no lo requieren. Este es el por qué:

    Pruebas futuras: no es necesario recordar @Injectable () cuando agreguemos una dependencia más adelante.

    Consistencia: todos los servicios siguen las mismas reglas, y no tenemos que preguntarnos por qué falta un decorador.

    Los inyectores también son responsables de crear instancias de componentes como HeroesComponent. ¿Por qué no hemos marcado HeroesComponent como @Injectable ()?

    Podemos agregarlo si realmente queremos. No es necesario porque HeroesComponent ya está marcado con @Component, y esta clase de decorador (como @Directive y @Pipe, de la que hablaremos más adelante) es un subtipo de InjectableMetadata. De hecho, los decoradores de metadatos inyectables identifican una clase como un objective para la creación de instancias por un inyector.

    Fuente: https://angular.io/docs/ts/latest/guide/dependency-injection.html