This feature especially useful if you want to store (and inject later on) some settings or configuration options. For example:
import { Container, Service, Inject } from'typedi';// somewhere in your global app parametersContainer.set('authorization-token','RVT9rVjSVN');@Service()classUserRepository { @Inject('authorization-token') authorizationToken:string;}
When you write tests you can easily provide your own "fake" dependencies to classes you are testing using set method: provide methods of the container:
Container.set(CoffeeMaker,newFakeCoffeeMaker());// or for named servicesContainer.set([ { id:'bean.factory', value:newFakeBeanFactory() }, { id:'sugar.factory', value:newFakeSugarFactory() }, { id:'water.factory', value:newFakeWaterFactory() },]);
You can create your services with the container using factory functions.
This way, service instance will be created by calling your factory function instead of instantiating a class directly.
import { Container, Service } from'typedi';functioncreateCar() {returnnewCar('V8');}@Service({ factory: createCar })classCar {constructor(public engineType:string) {}}// Getting service from the container.// Service will be created by calling the specified factory function.constcar=Container.get(Car);console.log(car.engineType); // > "V8"
Using factory class to create service
You can also create your services using factory classes.
This way, service instance will be created by calling given factory service's method factory instead of instantiating a class directly.
This code will not work, because Engine has a reference to Car, and Car has a reference to Engine. One of them will be undefined and it cause errors. To fix them you need to specify a type in a function this way:
You can group multiple services into single group tagged with service id or token. For example:
// Factory.tsexportinterfaceFactory {create():any;}// FactoryToken.tsexportconstFactoryToken=newToken<Factory>('factories');// BeanFactory.ts@Service({ id: FactoryToken, multiple:true })exportclassBeanFactoryimplementsFactory {create() {console.log('bean created'); }}// SugarFactory.ts@Service({ id: FactoryToken, multiple:true })exportclassSugarFactoryimplementsFactory {create() {console.log('sugar created'); }}// WaterFactory.ts@Service({ id: FactoryToken, multiple:true })exportclassWaterFactoryimplementsFactory {create() {console.log('water created'); }}// app.ts// now you can get all factories in a single arrayContainer.import([BeanFactory, SugarFactory, WaterFactory]);constfactories=Container.getMany(FactoryToken); // factories is Factory[]factories.forEach(factory =>factory.create());
Using multiple containers and scoped containers
By default all services are stored in the global service container, and this global service container holds all unique instances of each service you have.
If you want your services to behave and store data inside differently, based on some user context (http request for example) - you can use different containers for different contexts. For example:
In this example controller1 and controller2 are completely different instances, and QuestionRepository used in those controllers are different instances as well.
Container.reset removes container with the given context identifier. If you want your services to be completely global and not be container-specific, you can mark them as global:
Remove registered services or reset container state
If you need to remove registered service from container simply use Container.remove(...) method. Also you can completely reset the container by calling Container.reset() method. This will effectively remove all registered services from the container.