import { key } from "./traits"; export interface IDestroyable { destroy(): void; } /** * @template S Карта доступных зависимостей */ export interface Resolver { /** * Функция для разрешения зависимостей, поддерживает создание фабричных методов, * отложенную активацию и значение по-умолчанию для сервисов * @template K Ключ сервиса из {@link S} * @template O Тип параметра {@link opts} используется для выведения типа * возвращаемого значения. * @param name Ключ сервиса, который будет разрешен. * @param {boolean=} opts.lazy Признак того, что требуется отложенная активация, * будет возвращен фабричный метод для получения зависимости. Если не указан, * то считается `false`. * @param {any=} opts.default Значение по умолчанию, если в контейнере указанный * сервис не зарегистрирован * @returns Либо фабричный метод для получения зависимости, либо значение зависимости * @throws Error Если зависимость не найдена и не предоставлено значение по-умолчанию */ (name: K, opts?: O): () => (O extends { default: infer T } ? T : never) | NonNullable; (name: K, opts?: O): (O extends { default: infer T } ? T : never) | NonNullable; } export type DepsMap = { [k in key]: Refs | keyof S; }; export type Refs = { [k in keyof S]: Ref; }[keyof S]; export type Ref = { name: K, lazy?: L, default?: D | null }; export type Lazy = L extends true ? () => T : T; export type InferDefault = T extends { default: infer D } ? D : never; export type Resolve = R extends keyof S ? NonNullable : R extends Ref ? K extends keyof S ? Lazy | InferDefault, L> : never : never; /** * Интерфейс для конфигурирования сервиса в контейнере */ export interface IDescriptorBuilder { /** Указывает фабрика для создания экземпляра сервиса, фабрика передается * в виде параметра. При вызове фабрике будет передан объект с зависимостями, * которые были предварительно указаны вызовами метода `wants(...)` * * Вызов данного метода завершает конфигурирование сервиса. * * @param f Фабрика для создания экземпляра сервиса */ factory(f: (refs: R) => T): void; /** * Используется для указания зависимостей, которые потребуются фабричному * методу при создании нового экземпляра сервиса. Данный метод может быть * вызван несколько раз подряд, при этом вызовы этого метода имеют * кумулятивный эффект. * * @template X Тип объекта с зависимостями, которые требуется получить при * создании экземпляра фабрики при помощи фабричного метода. * @param refs Объект с описанием зависимостей * @returns Возвращает дескриптор сервиса, в котором указаны необходимые * зависимости */ wants & Record>(refs: X): IDescriptorBuilder; }, O> override(name: K, builder: RegistrationBuilder>): this; override(services: { [name in K]: RegistrationBuilder> }): this; lifetime(lifetime: "singleton", typeId: string | number | object): this; lifetime(lifetime: ILifetime | Exclude): this; /** Указывает функцию для освобождения экземпляра сервиса для случаев, когда * время жизни привязано к контейнеру. */ cleanup(cb: (item: T) => void): this; /** * Регистрирует в контейнере постоянное значение в качестве реализации сервиса. * * @param v Экземпляр реализации сервиса. */ value(v: T): void; } export type RegistrationBuilder = (d: IDescriptorBuilder>) => void; export type RegistrationBuildersMap, K extends keyof S = keyof S> = { [k in K]-?: RegistrationBuilder, NonNullable> }; export interface Descriptor { activate(context: IActivationContext): T; } export interface IActivationContext extends ServiceLocator { createLifetime(): ILifetime; createContainerLifetime(): ILifetime; } export type RegistrationMap = { [k in K]-?: Descriptor; }; export interface ContainerProvided { container: ServiceLocator>; childContainer: IContainerBuilder; } export type Configurable = { [k in keyof S]: k extends ProvidedKeys ? never : S[k]; }; export type ProvidedKeys = keyof ContainerProvided; export type ContainerServices = { [k in keyof S as k extends ProvidedKeys ? never: k]: S[k] } & ContainerProvided; export type ConfigurableKeys = Exclude; export type ConfigurableServices = Pick>; export type ContainerKeys = keyof S | ProvidedKeys; export interface ServiceLocator { resolve(name: K): NonNullable; resolve(name: K, def: T): NonNullable | T; } export interface LifetimeContainer { createLifetime(): ILifetime; } export interface ServiceContainer extends ServiceLocator>, IDestroyable { createChildContainer(): IContainerBuilder; } export interface IContainerBuilder { createServiceBuilder(name: K): IDescriptorBuilder, object, keyof S>; build(): ServiceContainer; } export type ActivationType = "singleton" | "container" | "hierarchy" | "context" | "call"; /** * Интерфейс для управления жизнью экземпляра объекта. Каждая регистрация имеет * свой собственный объект `ILifetime`, который создается при первой активации */ export interface ILifetime { /** Проверяет, что уже создан экземпляр объекта */ has(): boolean; get(): T; initialize(context: IActivationContext): void; store(item: T, cleanup?: (item: T) => void): void; } export type ExtractRequired = { [p in K as (undefined extends T[p] ? never : p)]-?: T[p] };