Declarative dependency injection for Javascript, inspired by Java's Dagger.
- Declarative. Dagger makes it easy to read and build complex applications. Annotate dependencies, compose them and Dagger handles the wiring and injections.
- Expressive. Few simple decorators, yet powerful. Use a minimalistic API extended by rich options chaining.
- Interoperable. Adopt as little or as much dependency injection as you want. Dagger helps improve class cohesion, loose coupling and testability.
$ yarn add @dagger-js/core
Babel is used to compile decorators syntax and maintain compatibility with old JS environments. Add the class, properties and parameter decorator plugins.
$ yarn add -D @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties babel-plugin-parameter-decorator
"plugins": [
["@babel/plugin-proposal-decorators", {"legacy": true}],
["@babel/plugin-proposal-class-properties", {"loose": true}],
"babel-plugin-parameter-decorator"
]
If you're using ESLint (and you probably should!), add the babel-eslint parser to run on Babel compiled code.
$ yarn add -D babel-eslint
"eslintConfig": {
"parser": "babel-eslint",
"parserOptions": {
"ecmaFeatures": {
"legacyDecorators": true
}
},
}
import { Provides } from "@dagger-js/core";
@Provides
class FoodService {
getFood = () => ["Apple"];
}
import { Singleton } from "@dagger-js/core";
@Singleton
class HeroService {
getHeroes = () => ["Saitama"];
}
Constructor Injection
import { Inject, Named } from "@dagger-js/core";
@Inject
class HeroAcademcy {
constructor(@Named("HeroService") heroService, water, @Named("FoodService") foodService) {
this.heroes = heroService.getHeroes();
this.water = water;
this.food = foodService.getFood();
}
}
const heroAcademy = new HeroAcademcy(undefined, ["Water"]);
console.log(heroAcademy.heroes); // ["Saitama"];
console.log(heroAcademy.water); // ["Water"];
console.log(heroAcademy.food); // ["Apple"];
Property Injection
import { Inject } from "@dagger-js/core";
import HeroService from "./HeroService";
class HeroAcademcy {
@Inject
heroService = HeroService; // Class
@Inject
HeroService = null;
@Inject.optional
godService = null;
@Inject.named("HeroService")
peopleService = null;
}
const heroAcademy = new HeroAcademcy();
console.log(heroAcademy.heroService.getHeroes()); // ["Saitama"];
console.log(heroAcademy.HeroService.getHeroes()); // ["Saitama"];
console.log(heroAcademy.godService); // null;
console.log(heroAcademy.peopleService.getHeroes()); // ["Saitama"];
Decorators are exported both capitalized and lower-case for convenience.
Extend your decorators with chainable options, chaining the same option twice will use the latter option.
Class decorator that declares a Class as Provider, creating new instances upon every injection.
- lazy - Instantiate instance lazily.
- Default: false
- named(name) - Register dependency under
name
.- Default: Class
Class decorator that declares a Class as Singleton, creating a single instance for every injection.
- lazy - Instantiate instance lazily.
- Default: false
- named(name) - Registers dependency under
name
.- Default: Class
Class or property injection decorator that injects on constructor parameters, or ClassType or PropertyKey respectively.
- computed - Computed property.
- Default: false.
- lazy - Computed property until invoked once, then becomes a static value.
- Default: false.
- optional - Injects
undefined
if not found.- Default: false
- named(name) - Injects dependency under
name
.- Default: Class
Note: Calling a constructor with provided values means Dagger won't override those values (unless
undefined
). This is by design.
Constructor parameter decorator used in conjunction with @Inject.
- optional - Injects
undefined
if not found.
Dagger is available under the MIT license. See LICENSE for details.