Statements that look like @SomeName
are decorators. Decorators
are a proposed extension to JavaScript. In short decorators let programmers
modify and/or tag methods, classes, properties and parameters. There is a lot
to decorators. In this section the focus will be on decorators relevant to DI:
@Inject
and @Injectable
. For more information on Decorators
please see the EcmaScript 6 and TypeScript Features section.
@Inject()
is a manual mechanism for letting Angular 2 know that a
parameter must be injected. It can be used like so:
import {Component, Inject, provide} from '@angular/core';
import {Hamburger} from '../services/hamburger';
@Component({
selector: 'app',
template: `Bun Type: {{ bunType }}`
})
export class App {
bunType: string;
constructor(@Inject(Hamburger) h) {
this.bunType = h.bun.type;
}
}
When using TypeScript, @Inject
is only needed for injecting primitives.
TypeScript's types let Angular 2 know what to do in most cases. The above
example would be simplified in TypeScript to:
import {Component, Inject, provide} from '@angular/core';
import {Hamburger} from '../services/hamburger';
@Component({
selector: 'app',
template: `Bun Type: {{ bunType }}`
})
export class App {
bunType: string;
constructor(h: Hamburger) {
this.bunType = h.bun.type;
}
}
@Injectable()
lets Angular 2 know that a class can be used with the
dependency injector. @Injectable()
is not strictly required if the class
has other Angular 2 decorators on it. What is important is that any class
that is going to be injected with Angular 2 is decorated. However best
practice is to decorate injectables with @Injectable()
, as it makes more
sense to the reader.
Here's an example of Hamburger
marked up with @Injectable
:
import {Injectable} from '@angular/core';
import {Bun} from './bun';
import {Patty} from './patty';
import {Toppings} from './toppings';
@Injectable()
export class Hamburger {
constructor(public bun: Bun, public patty: Patty, public toppings: Toppings) {
}
}
In the above example Angular 2's injector determines what to inject into
Hamburger
's constructor by using type information. This is possible because
these particular dependencies are typed, and are not primitive types.
In some cases Angular 2's DI needs more information than just types.