Depined is a dependency injection tool for JavaScript and TypeScript. It is a lightweight solution with full typing support.
- Awesome testability
- Works great for JavaScript
- Works even better for TypeScript without (beta) annotation and type casting
- Only needed dependencies are being build
- Works with interfaces, classes, functions, promises and constants
- Get typescript errors if the dependencies change without accidentally calling some io as with mocking
npm install depined
or
yarn add depined
The general idea is to write functions or classes without having strongly coupled dependencies (except for the interfaces). For example, make sure all dependencies are made available via parameters or the constructor.
Here are some code examples:
// Start by making a container
const container = depined()
// This container is empty and will always be empty because injecting stuff creates a new container, it never changes the current one.
// The main way to use Depined is to call the inject function. it needs 2 arguments, first is the token (should always be unique, second is the actual generator for the function or class)
const filledContainer = container.inject('logger', () => console.log)
// We can use everying in the container to initialize the next function/class
const containerWithClass = filledContainer.inject('class', ({logger}) => new ClassThatNeedsALogger(logger))
// When everying is injected, call the resolve and use it.
const di = await container.resolve()
// di.class is the initialized ClassThatNeedsALogger
const container = await depined()
.inject('logger', () => console.log)
.inject('class', ({logger}) => new ClassThatNeedsALogger(logger))
.resolve()
const container = await depined()
.set('config', 'secret')
.inject('dep', ({ config }) => `hello ${config}`)
.resolve()
container.dep // 'hello secret'
const container = await depined()
.inject('dbConfig', async () => {
const secret = await getSecret();
return secret.connectionString;
})
.inject('dbConnection', async ({dbConfig}) => new Connection(await dbConfig))
.resolve()
container.dbConnection // Connection class with the async configuration
const configDi = depined()
.set('config', 'secret')
const main = await depined()
.combine(await configDi.resolve())
.inject('connect', ({ config }) => `connect with config: "${config}"`)
.resolve()
main.connect // 'connect with config: "secret"'
Check out the unit tests: tests/depined.test.ts
- Create a test for your function
- Develop the function
- Add types for your dependencies as you need them
- Implement the dependencies starting at 1.