A lightweight dependency injection framework for TypeScript
npm install --save lepton-di
;// Declare an interface// Declare a "physical" symbol for us to bind to. (See below); // Or whatever clever schema you wish.// Build a concrete class// Create a class which uses our implementation// Create a new container and register our type;container.registerILogger.toClassConsoleLogger.withLifetime.Singleton;using container.beginScope,;
Declare your interfaces as you normally would in TypeScript
Because TypeScript interfaces do not generate any actual code, we need a symbol to bind to.
You can then register this symbol with a concrete class.
I prefer to keep the concrete classes only visible through a configuration function that I then export. This lets me keep as much of the module's concerns contained completely in that scope and not elsewhere.
Dependent classes may declare their dependencies in their properties or via a constructor parameter:
You have three choices on how to get parameters injected into these classes.
The first is to register them like you would with an interface.
Another other option is to use buildUp() to inject values in an already existing object.
The third option is to have the resolver get passed in as a parameter:
You can register a function or lambda as a factory method as well if you need to.
container.registerIWidget.toFactorynew Widgetsprocket, ISprocket;
Lepton has various utilites for managing object lifetimes. Objects can have one of three lifecycles:
Transient - This is the default lifetime of a registered class. Transient objects are not managed by the scope, they are simply created and returned.
Scoped - Scoped objects have their lifetimes tied to the life of the scope that created them. Once the scope is destroied, those objects will also be destroied.
Singleton - A singleton object will be created once per container, which are for the lifetime of the application.
Scopes is the first and most prominant of these. A scope holds (or creates) objects until that scope is destroyed.
Scopes can be nested with subsequent calls to beginScope(). Child scopes will walk up their parent chain and create a new instance of an object if not found.
If the item cannot be found a new instance will be created for the caller and saved.
If a class exposes a dispose() method, then Lepton will call this method when the owning scope of an object is destroied.
The using method is a utility method that ensures that an object's dispose method gets called; regardless if an exception is thrown or not.
The scope exposes an IResolver interface with the following functions:
This will inject properties into an already instantiated object. This is handy when you have a factory method for a class or other means of creating the object outside of the scope.
This method will not add the object to the scope's management.
This is similar to build up, but the object needs to be registered; it will also be added to the scope's management list, so it will be cleaned up when the scope goes out of context.
This will resolve a new or existing object from the scope's management.