The following article is about inversion of control(IoC) and dependency injection(DI) in Typescript. The main aims of that techniques is to provide loose coupling between modules and classes.
IoC and DI are part of the SOLID topics, SOLID principles using Typescript can gives you more notions about SOLID combined with the Typescript world.
I have already written about Dependency injection: Dependency Injection overview. The article contains some general informations about Dependency injection base concepts.
I also suggest another cool explanation of Dependency injection: How to explain dependency injection to a 5-year-old? .
Reasons for use Inversion of control and Dependency Injection
Here are some reasons for use Inversion of control and Dependency injection:
- Decoupling: dependency injection makes your modules less coupled resulting in a more maintainable codebase;
- Easier unit testing: instead of using hardcoded dependencies you can pass them into the module you would like to use;
- Faster development: with dependency injection, after the interfaces are defined it is easy to work without any merge conflicts;
InversifyJS has been developed with 4 main goals:
- Facilitate and encourage the adherence to the best OOP and IoC practices.
- Add as little runtime overhead as possible.
- Provide a state of the art development experience.
Inversify JS in action
The following example will use Typescript combined with InversifyJS to implement some basic logics. All classes will implement interfaces. An unit tests suite, written over Jest, will cover all the code base. It will use Dependency injection to mock behaviours and functions behind the classes.
Firstly, let’s give you an overview of the project structure:
Track class defines the Domain model of our system. The
IMusicRepository defines an independent interface which aim is to expose repository common functions, such as CRUD operations. The
VinylCatalog class implements the
IMusicRepository and query a fake db which it will return/update an collection of vinyl. Each
IMusicRepository consumer, for example
MusicCatalogService, does not know anything about
VinylCatalog: this is one of the main aims of the SOLID programming principles and Dependency injection.
The following code shows the typescript implementation of the previous UML schema:
Let’s create the Installer module:
@ line 9 we can find the mapping between the
VinylCatalog. InversifyJs also require to decorate our concrete class with the
@injectable attribute, like this:
At least, we can implement our composition root (It will be implemented in a main file for demo purpose):
Unit Testing all the things
Jest also offers an mocking built-in library, it will be useful in our demo to mock up the repository functions. Let’s get started by testing the
The previous test covers the
MusicCatalogService.get. First of all, it generates the mock result for the method
get. Secondly, it initialize the
MusicCatalogServices by using the generated mock.
Finally, we can test others method of
MusicCatalogService by using the same pattern:
You can find the following demo on GitHub.
In conclusion, I think we should follow those suggestions:
For more informations:
SOLID principles using Typescript