What Does Angular's @Injectable Decorator Mean?
I have been using the @Injectable
decorator since 2016 with the understanding that it was to indicate that the component/service I am decorating with @Injectable
is able to be injected into other services and components. The Angular Documentation on Injectable says it is “A marker metadata that marks a class as available to Injector
for creation”. The documentation goes on to say:
Injector
will throw an error when trying to instantiate a class that does not have@Injectable
marker, as shown in the example below.
And here is their example that should throw an error:
It seems straightforward, right? Wrong. The documentation is incorrect and that isn’t what Injectable
means at all. Take a look at this issue on GitHub. The important part is this comment by Pawel Kozlowski:
Yes, the documentation should be fixed.
@Injectable
is needed if you want to inject things into a service.
Let’s Test It Ourselves
Let’s arrange a test that the documentation said should throw an exception. First, we create a UsefulService
that does not have the @Injectable
decorator:
Then add a provider to my AppModule
:
And next, inject it into my AppComponent
:
No exception. Our service was injected just fine. And just to be sure nothing untoward happened during injection, I am using a string from the service in my component. Next, I wanted to see if I could get an exception to be thrown if I tried to inject UsefulService
into another service:
That code throws the following error:
Error in …/@angular/compiler@6.0.0/bundles/compiler.umd.js (301:17) Can’t resolve all parameters for Service2: (?).
You can test this yourself using a StackBlitz I created.
So, why does injection work in AppComponent
? Because the @Component decorator inherits from the @Directive decorator, which itself has an injector
. The fact that we set up a provider
is the important bit here because that means anything downstream from our main @NgModule
will be able to have our class injected as long as it has an injector
. From the docs:
Injectors are created for NgModules automatically as part of the bootstrap process and are inherited through the component hierarchy.
You can also inject your service using @Inject
in your constructor without decorating your class with @Injectable
like this:
So What about Their Example Test?
The documentation references this test:
That code does throw an exception. But not because UsefulService
doesn’t have the @Injectable
decorator. It throws because NeedsService
doesn’t have an Injector
that provides UsefulService
. In fact, in that same suite of tests they have a test to verify that you can inject a service that does not have the @Injectable
decorator:
Wrapping Up
@Injectable
still has use in configuring injection in the context of providers and scoping. And of course it allows injection into your services (if you aren’t using the @Inject
syntax instead). Hopefully the Angular docs will be fixed and that test updated or removed.