interfaces.ts
276 lines
| 11.6 KiB
| video/mp2t
|
TypeScriptLexer
|
|
r13 | import { ContainerBuilder } from "./ContainerBuilder"; | |
|
|
r4 | import { key } from "./traits"; | |
|
|
r1 | ||
|
|
r0 | export interface IDestroyable { | |
| destroy(): void; | |||
| } | |||
|
|
r1 | /** | |
| * @template S Карта доступных зависимостей | |||
| */ | |||
|
|
r8 | export interface Resolver<S> { | |
|
|
r1 | /** | |
| * Функция для разрешения зависимостей, поддерживает создание фабричных методов, | |||
| * отложенную активацию и значение по-умолчанию для сервисов | |||
|
|
r9 | * @template K Ключ сервиса из {@linkcode S} | |
| * @template O Тип параметра {@linkcode opts} используется для выведения типа | |||
|
|
r1 | * возвращаемого значения. | |
| * @param name Ключ сервиса, который будет разрешен. | |||
| * @param {boolean=} opts.lazy Признак того, что требуется отложенная активация, | |||
| * будет возвращен фабричный метод для получения зависимости. Если не указан, | |||
| * то считается `false`. | |||
| * @param {any=} opts.default Значение по умолчанию, если в контейнере указанный | |||
| * сервис не зарегистрирован | |||
| * @returns Либо фабричный метод для получения зависимости, либо значение зависимости | |||
| * @throws Error Если зависимость не найдена и не предоставлено значение по-умолчанию | |||
| */ | |||
|
|
r9 | <K extends keyof S, O extends { lazy: true; }>(name: K, opts?: O): () => NonNullable<S[K]> | InferDefault<O>; | |
| <K extends keyof S, O extends { lazy?: false; }>(name: K, opts?: O): NonNullable<S[K]> | InferDefault<O>; | |||
|
|
r0 | } | |
|
|
r8 | export type DepsMap<S> = { | |
| [k in key]: Refs<S> | keyof S; | |||
|
|
r7 | }; | |
|
|
r8 | export type Refs<S> = { | |
|
|
r9 | [k in keyof S]: Ref<k, S[k]>; | |
|
|
r8 | }[keyof S]; | |
|
|
r7 | ||
|
|
r9 | export type Ref<K extends key, D> = { | |
| /** The name of the service */ | |||
| name: K; | |||
| /** Make a lazy reference, the resolved dependency will be a function */ | |||
| lazy?: boolean; | |||
| /** The default value for the case where the service isn't defined. | |||
| * When specified the dependency becomes optional, the default value can be | |||
| * `null` or `undefined` | |||
| */ | |||
| default?: D | null | |||
| }; | |||
|
|
r4 | ||
|
|
r7 | export type Lazy<T, L extends boolean> = L extends true ? () => T : T; | |
|
|
r9 | /** Возвращает тип свойства `default` в типе {@link T} */ | |
|
|
r7 | export type InferDefault<T> = T extends { default: infer D } ? D : never; | |
|
|
r4 | ||
|
|
r9 | export type InferLazy<R> = R extends { lazy: infer L } ? | |
| L extends true ? true : false : | |||
| false; | |||
|
|
r8 | export type Resolve<S, R> = | |
|
|
r7 | R extends keyof S ? NonNullable<S[R]> : | |
|
|
r9 | R extends Ref<infer K, unknown> ? | |
| K extends keyof S ? | |||
| Lazy<NonNullable<S[K]> | InferDefault<R>, InferLazy<R>> : | |||
|
|
r8 | never : | |
|
|
r7 | never; | |
|
|
r4 | ||
|
|
r8 | /** | |
|
|
r9 | * Интерфейс для конфигурирования сервиса в контейнере. Конфигурирование сервиса | |
| * состоит из настройки различных параметров вызовами методов {@linkcode wants}, | |||
| * {@linkcode lifetime}, {@linkcode override}, {@linkcode cleanup}. Завершение настройки | |||
| * сервиса осуществляется вызовом одного из методов {@linkcode factory} либо | |||
| * {@linkcode value}. | |||
| * | |||
| * @template S Карта сервисов контейнера, доступных при описании дескриптора | |||
| * @template T Тип сервиса | |||
| * @template R Карта зависимостей, которая передается параметром фабрике | |||
| * @template U Имена пользовательских сервисов, доступных для переопределения | |||
|
|
r8 | */ | |
|
|
r9 | export interface IDescriptorBuilder<S, T, R, U extends keyof S> { | |
|
|
r1 | ||
|
|
r8 | /** Указывает фабрика для создания экземпляра сервиса, фабрика передается | |
| * в виде параметра. При вызове фабрике будет передан объект с зависимостями, | |||
| * которые были предварительно указаны вызовами метода `wants(...)` | |||
|
|
r1 | * | |
|
|
r8 | * Вызов данного метода завершает конфигурирование сервиса. | |
| * | |||
|
|
r9 | * @param f Фабрика для создания экземпляра сервиса. | |
|
|
r1 | */ | |
|
|
r9 | factory(f: (refs: R) => NonNullable<T>): void; | |
|
|
r4 | ||
|
|
r8 | /** | |
| * Используется для указания зависимостей, которые потребуются фабричному | |||
| * методу при создании нового экземпляра сервиса. Данный метод может быть | |||
| * вызван несколько раз подряд, при этом вызовы этого метода имеют | |||
| * кумулятивный эффект. | |||
| * | |||
| * @template X Тип объекта с зависимостями, которые требуется получить при | |||
| * создании экземпляра фабрики при помощи фабричного метода. | |||
| * @param refs Объект с описанием зависимостей | |||
| * @returns Возвращает дескриптор сервиса, в котором указаны необходимые | |||
| * зависимости | |||
| */ | |||
|
|
r7 | wants<X extends DepsMap<S> & Record<keyof R & keyof X, never>>(refs: X): | |
|
|
r4 | IDescriptorBuilder<S, T, R & { | |
|
|
r7 | [k in keyof X]: Resolve<S, X[k]>; | |
|
|
r9 | }, U> | |
|
|
r0 | ||
|
|
r9 | override<K extends U>(name: K, builder: BuildDescriptorFn<S, S[K], U>): this; | |
| override<X extends ConfigurationMapConstraint<S, U, keyof X>>(services: X): this; | |||
|
|
r0 | ||
|
|
r1 | lifetime(lifetime: "singleton", typeId: string | number | object): this; | |
| lifetime(lifetime: ILifetime<T> | Exclude<ActivationType, "singleton">): this; | |||
|
|
r0 | ||
|
|
r8 | /** Указывает функцию для освобождения экземпляра сервиса для случаев, когда | |
| * время жизни привязано к контейнеру. | |||
| */ | |||
|
|
r0 | cleanup(cb: (item: T) => void): this; | |
|
|
r8 | /** | |
| * Регистрирует в контейнере постоянное значение в качестве реализации сервиса. | |||
| * | |||
| * @param v Экземпляр реализации сервиса. | |||
| */ | |||
|
|
r9 | value(v: NonNullable<T>): void; | |
|
|
r0 | } | |
|
|
r9 | export type BuildDescriptorFn<S, T, U extends keyof S> = (d: IDescriptorBuilder<S, T, Record<never, never>, U>) => void; | |
|
|
r0 | ||
|
|
r9 | /** | |
| * Конфигурация контейнера, состоит из набора функций, которые выполняют конфигурацию. | |||
| * | |||
| * Все параметры конфигурации являются обязательными, если требуется ввести | |||
| * необязательные параметры, то нужно ограничить параметр типа {@linkcode K} | |||
| * | |||
| * @template S Сервисы доступные в контейнере | |||
| * @template K Сервисы участвующие в конфигурации | |||
| */ | |||
| export type ConfigurationMap<S, K extends keyof S, U extends keyof S> = { | |||
| [k in K]-?: BuildDescriptorFn<S, S[k], U> | |||
| }; | |||
| export type ConfigurationMapConstraint<S, U extends keyof S, X extends string | number | symbol> = { | |||
| [k in X]-?: k extends U ? BuildDescriptorFn<S, S[k], U> : never; | |||
| }; | |||
| /** | |||
| * The type constraint useful to restrict type parameters to prevent defining | |||
| * the services with the {@link ContainerKeys} names. | |||
| * | |||
| * The constraint doesn't exclude using this keys but declares them as `never` | |||
| * which effectively will lead using this keys to the error. | |||
| */ | |||
| export type ContainerServicesConstraint<S> = { | |||
| [k in keyof S]: k extends ContainerKeys ? never : S[k]; | |||
|
|
r1 | }; | |
|
|
r0 | ||
|
|
r8 | export interface Descriptor<S, T> { | |
|
|
r9 | ||
|
|
r13 | /** The level of the service in the containers chain. | |
| */ | |||
| readonly level: number; | |||
|
|
r9 | /** This flags indicates that this registration can be replaced or overridden. */ | |
| readonly configurable?: boolean; | |||
| /** If specified signals the activation context that a new service scope | |||
| * should be created to isolate service overrides. | |||
| */ | |||
| readonly hasOverrides?: boolean; | |||
| activate(context: IActivationContext<S>): NonNullable<T>; | |||
|
|
r0 | } | |
|
|
r10 | /** The context used to initialize lifetime instance {@linkcode ILifetime} */ | |
| export interface ILifetimeContext { | |||
|
|
r13 | ||
| ownerSlot<T>(slotId: string | number): ILifetimeSlot<T>; | |||
|
|
r12 | contextSlot<T>(slotId: string | number): ILifetimeSlot<T>; | |
|
|
r5 | ||
|
|
r12 | containerSlot<T>(slotId: string | number): ILifetimeSlot<T>; | |
|
|
r5 | ||
|
|
r10 | } | |
| export interface IActivationContext<S> extends ILifetimeContext, ServiceLocator<S> { | |||
|
|
r9 | register<K extends keyof S>(name: K, service: DescriptorMap<S>[K]): void; | |
|
|
r11 | ||
| fail(error: unknown): never; | |||
|
|
r13 | ||
| selfContainer(): ServiceLocator<S>; | |||
| createChildContainer(): IContainerBuilder<S, Exclude<keyof S, ContainerKeys>>; | |||
|
|
r1 | } | |
|
|
r9 | /** | |
| * Descriptors map for the specified services {@linkcode S}. All entries are | |||
| * optional regardless the required or optional services in the original map. | |||
| * | |||
| * @template S Сервисы контекста активации | |||
| * @template U Карта сервисов которые создаются дескрипторами | |||
| */ | |||
| export type DescriptorMap<S> = { | |||
| [k in keyof S]?: Descriptor<S, S[k]>; | |||
| }; | |||
|
|
r1 | ||
|
|
r9 | type ContainerKeys = keyof ContainerProvided<object>; | |
|
|
r13 | export type ContainerProvided<S, U extends keyof S = keyof S> = { | |
| container: ServiceLocator<ContainerProvided<S>>; | |||
|
|
r9 | ||
|
|
r13 | childContainer: IContainerBuilder<S, U>; | |
|
|
r9 | }; | |
|
|
r1 | ||
|
|
r9 | /** | |
| * Таблица сервисов, которые предоставляет контейнер. | |||
| * | |||
| * Сервисы, предоставляемые контейнером не могут быть null или undefined. | |||
| */ | |||
|
|
r13 | export type ContainerServices<S> = { | |
| [k in (keyof S) | ContainerKeys]: | |||
|
|
r12 | k extends ContainerKeys ? ContainerProvided<S>[k] : | |
| k extends keyof S ? S[k] : never | |||
|
|
r9 | }; | |
|
|
r1 | ||
|
|
r0 | ||
|
|
r9 | /** | |
| * Returns the service declared in the type map {@link S}. | |||
| * | |||
| * | |||
| */ | |||
|
|
r8 | export interface ServiceLocator<S> { | |
|
|
r1 | resolve<K extends keyof S>(name: K): NonNullable<S[K]>; | |
| resolve<K extends keyof S, T>(name: K, def: T): NonNullable<S[K]> | T; | |||
|
|
r0 | } | |
|
|
r1 | ||
|
|
r9 | export interface IContainerBuilder<S, U extends keyof S> { | |
| createServiceBuilder<K extends U>(name: K): | |||
| IDescriptorBuilder<S, S[K], Record<never, never>, U>; | |||
|
|
r1 | ||
|
|
r9 | build(): ServiceLocator<S>; | |
|
|
r0 | } | |
| export type ActivationType = "singleton" | "container" | "hierarchy" | "context" | "call"; | |||
| /** | |||
| * Интерфейс для управления жизнью экземпляра объекта. Каждая регистрация имеет | |||
| * свой собственный объект `ILifetime`, который создается при первой активации | |||
| */ | |||
|
|
r12 | export type ILifetime<T> = (context: ILifetimeContext) => ILifetimeSlot<NonNullable<T>>; | |
|
|
r0 | ||
|
|
r12 | export interface ILifetimeSlot<T> { | |
| readonly has: () => boolean; | |||
| readonly get: () => T; | |||
|
|
r9 | ||
|
|
r12 | readonly initialize: () => void; | |
| readonly store: (item: T, cleanup?: (item: T) => void) => void; | |||
|
|
r9 | ||
|
|
r12 | readonly remove: () => void; | |
|
|
r1 | ||
|
|
r12 | readonly cleanup: () => void; | |
|
|
r9 | } | |
|
|
r0 | ||
|
|
r9 | export interface ILifetimeManager extends IDestroyable { | |
|
|
r12 | slot<T>(id: string | number): ILifetimeSlot<T>; | |
|
|
r1 | } | |
|
|
r0 | ||
|
|
r2 | export type ExtractRequired<T, K extends keyof T = keyof T> = { [p in K as (undefined extends T[p] ? never : p)]-?: T[p] }; | |
|
|
r1 | ||
|
|
r9 | export type ExtractRequiredKeys<T, K extends keyof T = keyof T> = { [p in K]-?: undefined extends T[p] ? never : p }[K]; |
