Angular Services : 3 Common Misconceptions About the @Injectable Decorator
WARNING: This article was written before Angular 6 and needs to be updated to the recent Angular versions. But it's still interesting to read.
With the rewrite of the Angular framework, from AngularJS to the new version, many concepts have been simplified by the Angular team.
In AngularJS we could use factories, services, providers, contants or values to define the same things, but in different ways. In Angular, you only have to learn the concept of Service
and you are ready to go.
Most of the time an Angular service is just a TypeScript class decorated with @Injectable
. But that doesn't allow us to define an Angular service as a TypeScript class annotated with the @Injectable
decorator. Unfortunately, more often than not, people think that the two previous statements can be equated.
In this article, I will go over three common misconceptions about the @Injectable
decorator.
Misconception 1: the @Injectable
decorator means that the class can be injected somewhere (in a constructor)
In English, injectable can be one of two things:
- an adjective: capable of being injected;
- a noun: a pharmaceutical preparation that can be injected.
It is very easy to think that @Injectable
implies the notion of something that can be injected somewhere because of the meaning of "injectable" in English. But that is not the case. The @Injectable
decorator DOES NOT mean that a class can be injected somewhere. The term @Injectable
is a little bit confusing. A better name for @Injectable
could have been @CanBeInjectedThings
but isn't it too long for a decorator name ?
Misconception 2: the @Injectable
decorator is what makes a service a service.
In most of the tutorials or courses available on the Internet, you will find services annotated with the @Injectable
decorator. If you use the Angular CLI to generate a service, you will find it decorated with @Injectable
. Although it is a best practice to mark all your services with the @Injectable
, many people think that this is what make a service what it is. But it's not.
What make a service a service is the fact that it is added to the providers array of either a component or a module.
Misconception 3: the @Injectable
decorator is required for services
If a service has injected dependencies, it "needs" to be annotated with the @Injectable
decorator. In reality, any TypeScript decorator will do the job. But we use the @Injectable
decorator specifically because of the semantic given to it by the Angular team and the Angular developers.
Technically speaking, you can actually make your own decorator and use it instead of the @Injectable
decorator and your services will still work. But using the @Injectable
will make your intent clear to your Angular peers.
What does the @Injectable
decorator really mean and why do we need it?
if we take a look at the Angular documentation, we can find
A marker metadata that marks a class as available to Injector for creation.
The @Injectable() decorator identifies a service class that might require injected dependencies.
First of all, you have to know that the @Injectable
is only "required" if your service has injected dependencies.
To prove that, let's write a simple service that does not have injected dependencies. We do that in 3 steps:
- We create the service class (without a decorator)
- Then we add it to the providers array of a module, the root module
- Finally we inject our service in a component, the root component
It works. We have successfully created an Angular service without the @Injectable
decorator. But things will break as soon we inject something into our service.
- Let's inject
HttpClient
into our service to fetch the data from a backend.
- What happens in the browser?
Our application is now broken: the Angular compiler can't resolve the HttpClient
parameter.
Solving this problem is as simple as adding the @Injectable
decorator to our TeamService
.
We need the @Injectable
decorator to make Dependency Injection work in Angular
The Angular Dependency Injection mechanism uses TypeScript types to know what to inject.
We write our Angular applications in TypeScript. Our class TeamService
depends on the HttpClient
service, Angular will use the type 'HttpClient
' to know what need to be injected into TeamService
.
But JavaScript doesn't have types, so when our code is transpiled into JavaScript, we lose that information.
The sole role of the @Injectable
decorator is to make Dependency Injection work (even without TypeScript). If a class is marked with any decorator, the TypeScript compiler will emit metadata about our class providing we have emitDecoratorMetadata
set to true in our tsconfig.json
file. In Angular we use the @Injectable
decorator for that purpose. It's a convention.
In this article, we went over three common misconceptions about the @Injectable
decorator used with Angular services. Then we talked about the true meaning of the @Injectable
and how it enables the Angular Dependency Injection Framework to work.
Do you know other misconceptions about the @Injectable
decorator ? Please let me know in the comments.
Thank you very much for reading.