Dependency Injection is a really nice feature of Angular, however, if you are used to code in C# or Java, you might be familiar with Dependency Inversion Principle, which helps to keep things a bit less coupled and a bit more organized. This principle is based on the idea that you should rather ask for abstraction than the implementation of the service itself. This can be helpful in numerous ways, so, let’s take a look at what we can do about that 🙂

Since you can tell Angular what to provide and especially when, it is really simple to define an “interface” for your service. “Interface” because an interface is not really supported here, since in Typescript it is not something that could be used at runtime. Therefore, a small hack is to create an abstract service as following:

export abstract class IService {
  public abstract getItems(): Observable<any>;
}

export class Service extends IService {
  ...
}

After that, we just tell our module to provide Service class when IService should be injected.

{
    provide: IService,
    useClass: Service
}

This way we can achieve a few advantages:

  • It will be much easier to re-implement (or mock) the service while your other components and services can only use the abstract part that has to be re-implemented.
  • Services or components can be provided with different implementations when needed. For example, you might have multiple components working with basic CRUD operations and each one of them communicates with different endpoints. Then you can easily specify that for CarsComponent extending CRUDComponent which needs ICRUDService, you want to provide CarsService which implements ICRUDService.

And disadvantages:

  • Slightly more code has to be written.
  • Abstract classes might increase bundle size.

Did I forget something or do you disagree? Please let me know in the comments!

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *