useFactory
Using useFactory
in Providers
The useFactory
option is the most powerful and flexible way to define dependencies in Depinjionary. It allows you to provide a factory function that creates and resolves the dependency, with full control over the instantiation process.
Features of useFactory
- Custom Instantiation Logic: You can define exactly how a dependency is created.
- Token Injection: The
injectTokens
option specifies the dependencies to be passed into the factory function. - Support for Asynchronous Factories: Factory functions can be
async
, allowing you to perform asynchronous operations (e.g., fetching data, initializing context) before resolving the dependency.
Example: Custom Dependency Creation
Here’s a simple example of how to use useFactory
to create a CalculatorService
dependency:
const providers = [
{
provide: CalculatorService,
injectTokens: [LoggerInterface, StorageInterface, 'CalculatorConfig'],
useFactory: (logger: LoggerInterface, storage: StorageInterface, config: CalculatorConfig) => {
return new CalculatorService(logger, storage, config);
}
}
];
const container = ContainerResolver.init(providers);
const calculator = await container.resolve<CalculatorService>(CalculatorService);
console.log(calculator.calculate(5, 10)); // Outputs: 15
In this example:
LoggerInterface
,StorageInterface
, and'CalculatorConfig'
are the tokens injected into the factory.- The factory function creates a new instance of
CalculatorService
using these injected dependencies.
Example: Asynchronous Factory
With useFactory
, you can also perform asynchronous tasks before resolving a dependency. For example:
const providers = [
{
provide: CalculatorService,
injectTokens: [LoggerInterface, StorageInterface, 'CalculatorConfig'],
useFactory: async (logger: LoggerInterface, storage: StorageInterface, config: CalculatorConfig) => {
const context: CalculatorContext = await CalculatorContextFactory(config).init();
return new CalculatorService(logger, storage, context);
}
}
];
const container = ContainerResolver.init(providers);
(async () => {
const calculator = await container.resolve<CalculatorService>(CalculatorService);
console.log(calculator.calculate(5, 10)); // Outputs: 15
})();
In this example:
- The factory function asynchronously initializes a
CalculatorContext
before creating theCalculatorService
. - This is particularly useful for dependencies requiring setup or fetching external data.
When to Use useFactory
- Complex Dependencies: When a dependency requires initialization logic or complex construction.
- Asynchronous Operations: When setup or configuration depends on async tasks (e.g., API calls, database initialization).
- Dynamic Creation: When the exact dependency creation logic depends on runtime conditions.
Key Notes
- Inject Tokens: Use the
injectTokens
option to specify which dependencies should be passed to the factory function. - Async Support: The factory function can be asynchronous; just ensure your application properly handles
Promise
resolutions when resolving dependencies. - Maximum Flexibility:
useFactory
gives you complete control over dependency creation, making it the most versatile provider option.