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:
Injectorwill throw an error when trying to instantiate a class that does not have
@Injectablemarker, 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.
@Injectableis 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
Then add a provider to my
And next, inject it into my
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 …/@firstname.lastname@example.org/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 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.