# HG changeset patch # User cin # Date 2023-02-22 17:23:50 # Node ID 80cb5668e4a72987ee3893e4f300c37442296498 # Parent 58282d42a47b06e0e30faa0d72e9aea86e696bca working on typings diff --git a/src/main/ts/FluentConfiguration.ts b/src/main/ts/FluentConfiguration.ts --- a/src/main/ts/FluentConfiguration.ts +++ b/src/main/ts/FluentConfiguration.ts @@ -3,7 +3,7 @@ import { ConfigurableKeys, ContainerServ import { ServiceContainer } from "./interfaces"; import { argumentNotNull, each, isKey } from "./traits"; -export class FluentConfiguration = ConfigurableKeys> { +export class FluentConfiguration = ConfigurableKeys> { private _builders: Partial> = {}; @@ -12,7 +12,7 @@ export class FluentConfiguration>>(): FluentConfiguration> { + declare>(): FluentConfiguration> { return this as FluentConfiguration>; } diff --git a/src/main/ts/interfaces.ts b/src/main/ts/interfaces.ts --- a/src/main/ts/interfaces.ts +++ b/src/main/ts/interfaces.ts @@ -7,7 +7,7 @@ export interface IDestroyable { /** * @template S Карта доступных зависимостей */ -export interface Resolver { +export interface Resolver { /** * Функция для разрешения зависимостей, поддерживает создание фабричных методов, * отложенную активацию и значение по-умолчанию для сервисов @@ -27,13 +27,13 @@ export interface Resolver(name: K, opts?: O): (O extends { default: infer T } ? T : never) | NonNullable; } -export type DepsMap = { - [k in key]: Refs +export type DepsMap = { + [k in key]: Refs | keyof S; }; -export type Refs = { +export type Refs = { [k in keyof S]: Ref; -}[keyof S] | keyof S; +}[keyof S]; export type Ref = { name: K, lazy?: L, default?: D | null }; @@ -41,21 +41,40 @@ export type Lazy = export type InferDefault = T extends { default: infer D } ? D : never; -export type Resolve = +export type Resolve = R extends keyof S ? NonNullable : - R extends Ref ? - K extends keyof S ? Lazy | InferDefault, L> : - never: + R extends Ref ? + K extends keyof S ? Lazy | InferDefault, L> : + never : never; -export interface IDescriptorBuilder { +/** + * Интерфейс для конфигурирования сервиса в контейнере + */ +export interface IDescriptorBuilder { - /** + /** Указывает фабрика для создания экземпляра сервиса, фабрика передается + * в виде параметра. При вызове фабрике будет передан объект с зависимостями, + * которые были предварительно указаны вызовами метода `wants(...)` * - * @param f + * Вызов данного метода завершает конфигурирование сервиса. + * + * @param f Фабрика для создания экземпляра сервиса */ factory(f: (refs: R) => T): void; + /** + * Используется для указания зависимостей, которые потребуются фабричному + * методу при создании нового экземпляра сервиса. Данный метод может быть + * вызван несколько раз подряд, при этом вызовы этого метода имеют + * кумулятивный эффект. + * + * @template X Тип объекта с зависимостями, которые требуется получить при + * создании экземпляра фабрики при помощи фабричного метода. + * @param refs Объект с описанием зависимостей + * @returns Возвращает дескриптор сервиса, в котором указаны необходимые + * зависимости + */ wants & Record>(refs: X): IDescriptorBuilder; @@ -67,50 +86,60 @@ export interface IDescriptorBuilder | Exclude): this; + /** Указывает функцию для освобождения экземпляра сервиса для случаев, когда + * время жизни привязано к контейнеру. + */ cleanup(cb: (item: T) => void): this; + /** + * Регистрирует в контейнере постоянное значение в качестве реализации сервиса. + * + * @param v Экземпляр реализации сервиса. + */ value(v: T): void; } -export type RegistrationBuilder = (d: IDescriptorBuilder>) => void; +export type RegistrationBuilder = (d: IDescriptorBuilder>) => void; export type RegistrationBuildersMap, K extends keyof S = keyof S> = { [k in K]-?: RegistrationBuilder, NonNullable> }; -export interface Descriptor { +export interface Descriptor { activate(context: IActivationContext): T; } -export interface IActivationContext extends ServiceLocator { +export interface IActivationContext extends ServiceLocator { createLifetime(): ILifetime; createContainerLifetime(): ILifetime; } -export type RegistrationMap = { +export type RegistrationMap = { [k in K]-?: Descriptor; }; -export interface ContainerProvided> { +export interface ContainerProvided { container: ServiceLocator>; childContainer: IContainerBuilder; } -export type Configurable = { [k in keyof S & (keyof ContainerProvided)]: never; }; +export type Configurable = { [k in keyof S]: k extends ProvidedKeys ? never : S[k]; }; export type ProvidedKeys = keyof ContainerProvided; -export type ContainerServices> = S & ContainerProvided; +export type ContainerServices = + { [k in keyof S as k extends ProvidedKeys ? never: k]: S[k] } & + ContainerProvided; -export type ConfigurableKeys = Exclude; +export type ConfigurableKeys = Exclude; -export type ConfigurableServices = Pick>; +export type ConfigurableServices = Pick>; -export type ContainerKeys> = keyof S | keyof ContainerProvided; +export type ContainerKeys = keyof S | ProvidedKeys; -export interface ServiceLocator { +export interface ServiceLocator { resolve(name: K): NonNullable; resolve(name: K, def: T): NonNullable | T; } @@ -119,14 +148,14 @@ export interface LifetimeContainer { createLifetime(): ILifetime; } -export interface ServiceContainer> extends +export interface ServiceContainer extends ServiceLocator>, IDestroyable { createChildContainer(): IContainerBuilder; } -export interface IContainerBuilder> { +export interface IContainerBuilder { createServiceBuilder(name: K): IDescriptorBuilder, object, keyof S>; build(): ServiceContainer; diff --git a/src/main/ts/traits.ts b/src/main/ts/traits.ts --- a/src/main/ts/traits.ts +++ b/src/main/ts/traits.ts @@ -1,7 +1,7 @@ import { FluentConfiguration } from "./FluentConfiguration"; import { IDestroyable } from "./interfaces"; -export function fluent() { +export function fluent() { return new FluentConfiguration(); } diff --git a/src/test/ts/t/container.ts b/src/test/ts/t/container.ts --- a/src/test/ts/t/container.ts +++ b/src/test/ts/t/container.ts @@ -1,7 +1,8 @@ /* eslint max-classes-per-file: ["error", 20] */ import { describe, it } from "mocha"; import { Container } from "../Container"; -import { ContainerServices, DepsMap, Refs, Resolver } from "../interfaces"; +import { ContainerBuilder } from "../ContainerBuilder"; +import { ConfigurableKeys, ContainerProvided, ContainerServices, DepsMap, Refs, Resolver } from "../interfaces"; import { fluent } from "../traits"; class Foo { @@ -20,6 +21,8 @@ interface Services { bar?: Bar; baz: Foo; + + container: string; } interface ServicesB { @@ -35,9 +38,18 @@ declare const resolver: Resolver>(m: X) => {}; +const mmap = >(m: X) => {}; + +declare const refs: Refs; -const refs: Refs = {name: "bar", default: undefined}; +if (refs && refs.name === "foo") { + refs.default; +} + +declare const x: ContainerServices; + +x.container.resolve("container"); + mmap({ fooz: {name: "foo", lazy: false, default: undefined }, @@ -56,6 +68,7 @@ const config = fluent() .declare() .declare() .register({ + zoo: it => {}, bar: it => it .lifetime("context") // тип активации, время жизни .wants({ @@ -77,11 +90,11 @@ const config = fluent() }) .done({}); -declare const container: Container; +declare const container: ContainerBuilder<{}>; const c2 = config.configure(container); c2.resolve("foo"); declare const m :ContainerServices<{foo: Foo}>["container"]; -m.resolve("container").resolve("container"); \ No newline at end of file +m.resolve("container").resolve("container").resolve("foo"); \ No newline at end of file