Using DI utils
With this library you can implement DI with next steps. First we need to define our tokens:
import { createToken } from '@krutoo/utils/di';
export const TOKEN = {
logger: createToken<Logger>(),
client: createToken<HttpClient>(),
};
Then we need to define "providers" - functions that returns component implementation:
import type { Resolve } from '@krutoo/utils/di';
import { TOKEN } from '#app/token';
export function provideLogger() {
return new MyLogger();
}
export function provideClient(resolve: Resolve) {
// here we use logger from container as dependency of client
const logger = resolve(TOKEN.logger);
return new HttpClient({
onError: logger.error,
});
}
The pitfall here is that you can pass the resolve function as an argument to another function to call it internally or even later. Don't do this! This will turn your container into a service locator, which is bad practice in most cases.
And now we need to create container and fill it by providers:
import { createContainer } from '@krutoo/utils/di';
import { provideClient, provideLogger } from '#app/providers';
import { TOKEN } from '#app/token';
export function createAppContainer() {
const container = createContainer();
container.set(TOKEN.client, provideClient);
container.set(TOKEN.logger, provideLogger);
return container;
}
Finally you can get components from container in any order and each component will automatically resolves its dependencies.
import { createAppContainer } from '#app/container';
import { TOKEN } from '#app/token';
const container = createAppContainer();
const client = container.get(TOKEN.client);
const response = await client.get('/api/user/me');
In this code client will automatically have type HttpClient because we use TOKEN.client to get it.
Error will thrown if container has not bound providers for this token or some dependencies missed.
A repeated attempt to resolve a component from a container will return exactly the same instance that was created once during the first attempt to resolve it.