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:

class UsefulService {}

class NeedsService {
  constructor(public service: UsefulService) {}
}

expect(() => ReflectiveInjector.resolveAndCreate([NeedsService, UsefulService])).toThrow();

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:

export class UsefulService {
  public message: string = 'Hello from UsefulService!';
}

Then add a provider to my AppModule:

providers: [ UsefulService ]

And next, inject it into my AppComponent:

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  messageFromUsefulService: string = '';
  // According to Angular docs, injecting `UsefulService` should throw an 
  // exception due to the fact that it doesn't have the @Injectable decorator.
  constructor(private usefulService: UsefulService) {
    this.messageFromUsefulService = usefulService.message;
  }
}

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:

export class Service2 {
  public message: string = 'Bonjour from Service 2!';
  constructor(private usefulService: UsefulService) {
  }
}

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:

export class MyService {
  constructor(@Inject(UsefulService) usefulService:UsefulService) {
  }
}

So What about Their Example Test?

The documentation references this test:

it('throws without Injectable', () => {
  // #docregion InjectableThrows
  class UsefulService {}

  class NeedsService {
    constructor(public service: UsefulService) {}
  }

  expect(() => ReflectiveInjector.resolveAndCreate([NeedsService, UsefulService])).toThrow();
  // #enddocregion
});

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:

it('works without decorator', () => {
  // #docregion InjectWithoutDecorator
  class Engine {}

  @Injectable()
  class Car {
    constructor(public engine: Engine) {
    }  // same as constructor(@Inject(Engine) engine:Engine)
  }

  const injector = ReflectiveInjector.resolveAndCreate([Engine, Car]);
  expect(injector.get(Car).engine instanceof Engine).toBe(true);
  // #enddocregion
});

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.