rsdi
Version:
TypeScript dependency injection container. Strong types without decorators.
70 lines (69 loc) • 2.98 kB
TypeScript
import { DenyInputKeys, Factory, IDIContainer, ResolvedDependencies, StringLiteral } from "./types";
/**
* Dependency injection container
*/
export declare class DIContainer<ContainerResolvers extends ResolvedDependencies = {}> {
private resolvers;
private resolvedDependencies;
private context;
/**
* Adds new dependency resolver to the container. If dependency with given name already exists it will throw an error.
* Use update method instead. It will override existing dependency.
*
* @param name
* @param resolver
*/
add<N extends string, R extends Factory<ContainerResolvers>>(name: StringLiteral<DenyInputKeys<N, keyof ContainerResolvers>>, resolver: R): IDIContainer<ContainerResolvers & {
[n in N]: ReturnType<R>;
}>;
/**
* Updates existing dependency resolver. If dependency with given name does not exist it will throw an error.
* In most cases you don't need to override dependencies and should use add method instead. This approach will
* help you to avoid overriding dependencies by mistake.
*
* You may want to override dependency if you want to mock it in tests.
*
* @param name
* @param resolver
*/
update<N extends keyof ContainerResolvers, R extends Factory<ContainerResolvers>>(name: StringLiteral<N>, resolver: R): IDIContainer<{
[P in Exclude<keyof ContainerResolvers, N>]: ContainerResolvers[P];
} & {
[n in N]: ReturnType<R>;
}>;
/**
* Checks if dependency with given name exists
* @param name
*/
has(name: string): boolean;
/**
* Resolve dependency by name. Alternatively you can use property access to resolve dependency.
* For example: const { a, b } = container;
* @param dependencyName
*/
get<Name extends keyof ContainerResolvers>(dependencyName: Name): ContainerResolvers[Name];
/**
* Extends container with given function. It will pass container as an argument to the function.
* Function should return new container with extended resolvers.
* It is useful when you want to split your container into multiple files.
* You can create a file with resolvers and extend container with it.
* You can also use it to create multiple containers with different resolvers.
*
* For example:
*
* const container = new DIContainer()
* .extend(addValidators)
*
* export type DIWithValidators = ReturnType<typeof addValidators>;
* export const addValidators = (container: DIWithDataAccessors) => {
* return container
* .add('myValidatorA', ({ a, b, c }) => new MyValidatorA(a, b, c))
* .add('myValidatorB', ({ a, b, c }) => new MyValidatorB(a, b, c));
* };
*
* @param f
*/
extend<E extends (container: IDIContainer<ContainerResolvers>) => any>(f: E): ReturnType<E>;
private setValue;
private toContainer;
}