An opinionated dependency injector container written in TypeScript for TypeScript developers.
- Highly opinionated. Only supports abstract or concrete types mapped to their implementations (including themselves).
- Type-safe with a good amount of compiler support (no magic strings, no convention based approach).
- Strict and explicit, meaning no silent fails or unexpected outcome for misconfigurations, no intransparent black magic.
- Supported scope kinds for type registrations: transient, singleton, instance, and factory functions (singleton/custom).
yarn add good-injectorornpm install good-injector
Create a container and register type mappings with it. Use the container later to resolve mapped types, including all of their dependency chain. Make sure target types are decorated with the included
;// map abstract types to concrete implementations.// compiler complains if ConsoleLogger does not extend Loggercontainer.registerTransientLogger, ConsoleLogger;// map types to themselves so the container can resolve them and their dependencies// compiler complains if MyCustomType cannot be constructedcontainer.registerTransientMyCustomType;// for successful resolution, MyCustomType must be decorated with injection support// resolve it. MyCustomType constructor receives a fresh instance of ConsoleLogger;
Use singleton registration if required:
Register already available instances (e.g. an object you received from somewhere else) as instance:
Register resolution strategies with factory functions. This allows you to apply any complex logic for resolving instances that are beyond the scope of the container:
You can also use singleton factories. This allows complex creation of singletons without the need to handle the lifetime logic yourself.
You can unregister registrations. Use case, for example: passing around data across a sub-system of your application, and removing it once that sub-system is left, or a workflow has been finished etc.
- Meta data for types in the same file are not emitted in a way that allows proper resolution. Make sure to put all classes used as constructor arguments for injection into separate files and export them.
Create an adapter for Vue.js.See good-injector-vue for the Vue.js adapter!
- Make the decorator register which types have been decorated. At the moment, with "reflect-metadata" you can't distinguish between "has been decorated and emitting metadata was not required" and "has not been decorated". This means that it's not possible to test whether someone has forgotton to decorate or if the correctly decorated type has not constructor arguments. This can be solved by registering decorated types by the decorator itself, and then tighten up the resolve implementation.
Adding more registration scopes, in particular for existing instances and factories. Both are valid use cases, to add things to the container you received from elsewhere, or to resolve types based on criteria that is out of scope for the container.Instance and factory function registrations have been added for version 0.2.0!
- Passing through arguments during resolution. This is a use case that came up a lot in the past, i.e. you want to resolve the dependencies of a type but there's one or more additional dynamic arguments that you need to pass on to the resolved type. A pattern to work around this is to use factories that set properties or call initialization methods on the resolved type. But it may be nice to have something like this built-in.
Make sure you have ts-node globally installed for executing the unit tests.
- Clone repo
npm run build:dev
Look at the available scripts in
package.json to see what's available to build, lint, test and watch.