Introduction: Dependency Injection(DI) might sound like a complex design pattern, but at its core, its a simple technique to make your code more modular, testable and maintainable. Lets look at how DI works in JavaScript and why it's worth using.
What is DI?
Its a pattern where an object or function receives its dependencies from the outside rather than creating them internally.
Without DI
class UserService{
constructor(){
this.api= new API();// tightly coupled
}
}
using DI
class UserService{
constructor(api){
this.api= api;// Dependency injected
}
}
here when we use DI userservice doesn't care how api is created- it gets and use when called.
Why use DI?
- Maintainability: You don’t hardcode dependencies — you swap them without rewriting core logic.
- Testability: You can inject mocks or stubs, making unit tests a breeze.
- Loose coupling: Your components/services aren’t stuck to concrete implementations.
Simple DI example in javaScript
js
// API service that fetches a user (mock implementation)
class API(){
getUser(){
return {id:1, name:'Priya khanna'}
}
}
//UserService depends on API but does not create it internally
class UserService(){
constructor(api){
this.api=api;// Dependency injected
}
getUserInfo(){
const user= this.api.getUser();
return 'User : ${user.name}- ${user.id}'
}
}
//application entry point
function main(){
const api= new API();//create the dependency
const userService= new UserService(api);// DI
console.log(userService.getUserInfo());
}
main();
Note:
- the API class simulates a service that returns the data.
UserService expects an API instance passed in- this is constructor injection.
this pattern makes UserService easily testable and decoupled from API
bash
node di-example.js
Key points:-
Dependency Injection (DI) isn’t exclusive to Angular; it’s a powerful design pattern used across many JavaScript frameworks and libraries to improve modularity, testability, and maintainability.
Here’s a quick overview of how DI appears beyond Angular:
React: While React doesn’t have a built-in DI system like Angular, you can achieve DI-like behavior using Context API or third-party libraries like InversifyJS or BottleJS. These let you inject dependencies into components or hooks, improving decoupling.
Vue.js: Vue supports DI through its provide/inject API, allowing parent components to provide dependencies that child components can inject, enabling flexible dependency management across component trees.
Svelte: Svelte offers a context API similar to Vue’s provide/inject, enabling simple dependency passing without prop drilling.
Node.js: On the backend, frameworks like NestJS (built on top of Express) implement DI extensively, inspired by Angular’s system, to manage service lifecycles and dependencies efficiently.
So, DI is a broadly applicable pattern in the JavaScript ecosystem, implemented differently depending on the framework’s architecture but always aiming to make code cleaner, more modular, and easier to test.
Top comments (0)