How to Use the @Injectable Decorator in Angular
Jul 3, 2020 • 5 Minute Read
Introduction
Which of the following statements about the @Injectable decorator seem valid to you?
- The @Injectable decorator should be added to each of the services.
- The @Injectable decorator should be added to any service that uses dependency injection (DI).
- The @Injectable decorator is not compulsory to add if you don’t use the ‘providedIn’ option.
- The @Injectable decorator together with the ‘providedIn’ option means the service should not be added within the providers’ array of a module.
The correct answers are 2 and 4. To find out why, keep reading this guide, where we will discuss the @Injectable decorator and its effect on DI in Angular.
Angular comes with its own DI framework and is used in the design of Angular apps to enhance their modularity as well as efficiency. @Injectable() is an important part of any Angular service definition. The reason some people might select the wrong answer to the question above is that they misjudge the relationship between the @Injectable decorator and DI in Angular, not understanding what this decorator truly does.
Adding @Injectable Is Not Registering the Service
You generally need two things for an inversion of control (IOC) container, which is used for DI. The first thing is a token. To register something with the IOC container, a token is necessary. A token is a unique thing to register any service. The second thing is a provider. A provider helps a DI container to create an instance of a specific dependency.
In Angular, registering a service using a token and passing it to a provider can be done in two different ways.
First, a service can be registered with a particular @NgModule. The process is to register by passing a service to the array of providers. In this case, the token used is the typescript type MyService. The provider here is useClass. This provider strategy informs that a certain dependency can be launched by new ... ()-ing it.
@NgModule({
...
providers: [
// long hand syntax
{provide: MyService, useClass: MyService},
// short hand syntax
MyService
],
})
As there is similarity between the token and the provider, you can utilize the short-hand syntax here.
Note: There are several other places like @NgModule where you can add a service of the providers array. The registering idea is equivalent to @Components and @Directives.
The use of the providedIn option is the other way that you can register a service.
@Injectable({
providedIn: 'root'
})
export class MyService {
constructor() { }
}
What About @Injectable?
I haven't properly described the @Injectable decorator yet. The reason is that the @Injectable decorator has nothing to do with registering service with the container. So what is the purpose of the @Injectable decorator?
Indeed, it is standard that MyService can have a few dependencies. For example, you can use the HttpClient.
import { HttpClient } from '@angular/common/http';
@Injectable()
export class MyService {
constructor(private httpClient: HttpClient) { }
}
Let's try to understand what happens when you need to get an instance of MyService. When Angular needs to create the service, it should pass it an instance of HttpClient. So how can it do that?
First of all, Angular should know which dependency is mentioned. Remember that you utilized a token to register a dependency? With the same token, you can ask Angular for an instance of that dependency. Therefore, Angular will investigate the constructor and see that a service is requested for the token HttpClient. And if a service is registered with that token, Angular can use that token to start MyService and give the instance it created.
var MyService = /** @class */ (function () {
function MyService(httpClient) {
this.httpClient = httpClient;
}
MyService = __decorate([
Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Injectable"])(),
__metadata(
"design:paramtypes",
[_angular_common_http__WEBPACK_IMPORTED_MODULE_1__["HttpClient"]]
)
], MyService);
return MyService;
}());
The important part here is that Angular isn't utilizing the @Injectable decorator to register the service.
Conclusion
The @Injectable decorator is linked to but not fundamentally necessary for every service when using DI in Angular. However, I admit the question is somewhat misleading in the sense that Option 2 from the introduction—"The @Injectable decorator should be added to any service that uses DI"—is not the ideal way to phrase it. It means a service having dependencies of its own. Further, it is always best to include a decorator anyway. There isn't generally an advantage to omitting it. If you add a dependency later, you may get some weird bugs.