| @@ -1,71 +1,71 | |||
|
|
1 | 1 | import { DescriptorBuilder } from "./DescriptorBuilder"; |
|
|
2 | 2 | import { ConfigurableKeys, ContainerServices, RegistrationBuildersMap, ExtractRequired, IContainerBuilder } from "./interfaces"; |
|
|
3 | 3 | import { ServiceContainer } from "./interfaces"; |
|
|
4 | 4 | import { argumentNotNull, each, isKey } from "./traits"; |
|
|
5 | 5 | |
|
|
6 |
export class FluentConfiguration<S |
|
|
|
6 | export class FluentConfiguration<S, Y extends ConfigurableKeys<S> = ConfigurableKeys<S>> { | |
|
|
7 | 7 | |
|
|
8 | 8 | private _builders: Partial<RegistrationBuildersMap<S>> = {}; |
|
|
9 | 9 | |
|
|
10 | 10 | /** Adds a declaration of the services to the current config. |
|
|
11 | 11 | * |
|
|
12 | 12 | * @template D The map of the services |
|
|
13 | 13 | * @returns self |
|
|
14 | 14 | */ |
|
|
15 |
declare<D extends |
|
|
|
15 | declare<D extends Pick<S, keyof D & keyof S>>(): FluentConfiguration<S & D, Y | ConfigurableKeys<D>> { | |
|
|
16 | 16 | return this as FluentConfiguration<S & D, Y | ConfigurableKeys<D>>; |
|
|
17 | 17 | } |
|
|
18 | 18 | |
|
|
19 | 19 | /** Adds compile-time information about the already provided services |
|
|
20 | 20 | * |
|
|
21 | 21 | * @template P The map of the provided services |
|
|
22 | 22 | * @returns self |
|
|
23 | 23 | */ |
|
|
24 | 24 | provided<P extends Pick<S, keyof P & keyof S>>(): FluentConfiguration<S & P, Exclude<Y, keyof P>> { |
|
|
25 | 25 | return this as FluentConfiguration<S & P, Exclude<Y, keyof P>>; |
|
|
26 | 26 | } |
|
|
27 | 27 | |
|
|
28 | 28 | /** Register the service. |
|
|
29 | 29 | * |
|
|
30 | 30 | * @param name The name of the service |
|
|
31 | 31 | * @param builder The service builder |
|
|
32 | 32 | * @returns self |
|
|
33 | 33 | */ |
|
|
34 | 34 | register<K extends Y>(name: K, builder: RegistrationBuildersMap<S>[K]): FluentConfiguration<S, Exclude<Y, K>>; |
|
|
35 | 35 | /** Registers the collection of services |
|
|
36 | 36 | * @param config The collection of services to register. |
|
|
37 | 37 | * @returns self |
|
|
38 | 38 | */ |
|
|
39 | 39 | register<K extends Y>(config: RegistrationBuildersMap<S, K>): FluentConfiguration<S, Exclude<Y, K>>; |
|
|
40 | 40 | register<K extends Y>(nameOrConfig: K | RegistrationBuildersMap<S, K>, builder?: RegistrationBuildersMap<S>[K]) { |
|
|
41 | 41 | if (isKey(nameOrConfig)) { |
|
|
42 | 42 | argumentNotNull(builder, "builder"); |
|
|
43 | 43 | this._builders[nameOrConfig] = builder; |
|
|
44 | 44 | } else { |
|
|
45 | 45 | each(nameOrConfig, (v, k) => this.register(k, v)); |
|
|
46 | 46 | } |
|
|
47 | 47 | |
|
|
48 | 48 | return this as FluentConfiguration<S, Exclude<Y, K>>; |
|
|
49 | 49 | } |
|
|
50 | 50 | |
|
|
51 | 51 | /** |
|
|
52 | 52 | * This method is used to enable a compile time check of the configuration. |
|
|
53 | 53 | * If there are not configured services in the configuration the compiler |
|
|
54 | 54 | * will trigger the error. |
|
|
55 | 55 | * |
|
|
56 | 56 | * @param missing Empty object literal should always be specified. |
|
|
57 | 57 | * @returns self |
|
|
58 | 58 | */ |
|
|
59 | 59 | // eslint-disable-next-line @typescript-eslint/no-unused-vars |
|
|
60 | 60 | done<M extends ExtractRequired<S,Y>>(missing: M) { |
|
|
61 | 61 | return this; |
|
|
62 | 62 | } |
|
|
63 | 63 | |
|
|
64 | 64 | configure<T extends IContainerBuilder<S>>(builder: T) { |
|
|
65 | 65 | each(this._builders, (v, k) => { |
|
|
66 | 66 | v(builder.createServiceBuilder(k)); |
|
|
67 | 67 | }); |
|
|
68 | 68 | builder.build() as T & ServiceContainer<S>; |
|
|
69 | 69 | } |
|
|
70 | 70 | |
|
|
71 | 71 | } |
| @@ -1,154 +1,183 | |||
|
|
1 | 1 | import { key } from "./traits"; |
|
|
2 | 2 | |
|
|
3 | 3 | export interface IDestroyable { |
|
|
4 | 4 | destroy(): void; |
|
|
5 | 5 | } |
|
|
6 | 6 | |
|
|
7 | 7 | /** |
|
|
8 | 8 | * @template S Карта доступных зависимостей |
|
|
9 | 9 | */ |
|
|
10 |
export interface Resolver<S |
|
|
|
10 | export interface Resolver<S> { | |
|
|
11 | 11 | /** |
|
|
12 | 12 | * Функция для разрешения зависимостей, поддерживает создание фабричных методов, |
|
|
13 | 13 | * отложенную активацию и значение по-умолчанию для сервисов |
|
|
14 | 14 | * @template K Ключ сервиса из {@link S} |
|
|
15 | 15 | * @template O Тип параметра {@link opts} используется для выведения типа |
|
|
16 | 16 | * возвращаемого значения. |
|
|
17 | 17 | * @param name Ключ сервиса, который будет разрешен. |
|
|
18 | 18 | * @param {boolean=} opts.lazy Признак того, что требуется отложенная активация, |
|
|
19 | 19 | * будет возвращен фабричный метод для получения зависимости. Если не указан, |
|
|
20 | 20 | * то считается `false`. |
|
|
21 | 21 | * @param {any=} opts.default Значение по умолчанию, если в контейнере указанный |
|
|
22 | 22 | * сервис не зарегистрирован |
|
|
23 | 23 | * @returns Либо фабричный метод для получения зависимости, либо значение зависимости |
|
|
24 | 24 | * @throws Error Если зависимость не найдена и не предоставлено значение по-умолчанию |
|
|
25 | 25 | */ |
|
|
26 | 26 | <K extends keyof S, O extends { lazy: true; default?: unknown }>(name: K, opts?: O): () => (O extends { default: infer T } ? T : never) | NonNullable<S[K]>; |
|
|
27 | 27 | <K extends keyof S, O extends { lazy?: false; default?: unknown }>(name: K, opts?: O): (O extends { default: infer T } ? T : never) | NonNullable<S[K]>; |
|
|
28 | 28 | } |
|
|
29 | 29 | |
|
|
30 |
export type DepsMap<S |
|
|
|
31 | [k in key]: Refs<S> | |
|
|
30 | export type DepsMap<S> = { | |
|
|
31 | [k in key]: Refs<S> | keyof S; | |
|
|
32 | 32 | }; |
|
|
33 | 33 | |
|
|
34 |
export type Refs<S |
|
|
|
34 | export type Refs<S> = { | |
|
|
35 | 35 | [k in keyof S]: Ref<k, boolean, S[k]>; |
|
|
36 |
}[keyof S] |
|
|
|
36 | }[keyof S]; | |
|
|
37 | 37 | |
|
|
38 | 38 | export type Ref<K extends key, L extends boolean, D> = { name: K, lazy?: L, default?: D | null }; |
|
|
39 | 39 | |
|
|
40 | 40 | export type Lazy<T, L extends boolean> = L extends true ? () => T : T; |
|
|
41 | 41 | |
|
|
42 | 42 | export type InferDefault<T> = T extends { default: infer D } ? D : never; |
|
|
43 | 43 | |
|
|
44 |
export type Resolve<S |
|
|
|
44 | export type Resolve<S, R> = | |
|
|
45 | 45 | R extends keyof S ? NonNullable<S[R]> : |
|
|
46 |
R extends Ref<infer K, infer L, unknown> ? |
|
|
|
47 |
|
|
|
|
48 |
|
|
|
|
46 | R extends Ref<infer K, infer L, unknown> ? | |
|
|
47 | K extends keyof S ? Lazy<NonNullable<S[K]> | InferDefault<R>, L> : | |
|
|
48 | never : | |
|
|
49 | 49 | never; |
|
|
50 | 50 | |
|
|
51 | export interface IDescriptorBuilder<S extends object, T, R extends object, O extends keyof S> { | |
|
|
51 | /** | |
|
|
52 | * Интерфейс для конфигурирования сервиса в контейнере | |
|
|
53 | */ | |
|
|
54 | export interface IDescriptorBuilder<S, T, R, O extends keyof S> { | |
|
|
52 | 55 | |
|
|
53 | /** | |
|
|
56 | /** Указывает фабрика для создания экземпляра сервиса, фабрика передается | |
|
|
57 | * в виде параметра. При вызове фабрике будет передан объект с зависимостями, | |
|
|
58 | * которые были предварительно указаны вызовами метода `wants(...)` | |
|
|
54 | 59 | * |
|
|
55 | * @param f | |
|
|
60 | * Вызов данного метода завершает конфигурирование сервиса. | |
|
|
61 | * | |
|
|
62 | * @param f Фабрика для создания экземпляра сервиса | |
|
|
56 | 63 | */ |
|
|
57 | 64 | factory(f: (refs: R) => T): void; |
|
|
58 | 65 | |
|
|
66 | /** | |
|
|
67 | * Используется для указания зависимостей, которые потребуются фабричному | |
|
|
68 | * методу при создании нового экземпляра сервиса. Данный метод может быть | |
|
|
69 | * вызван несколько раз подряд, при этом вызовы этого метода имеют | |
|
|
70 | * кумулятивный эффект. | |
|
|
71 | * | |
|
|
72 | * @template X Тип объекта с зависимостями, которые требуется получить при | |
|
|
73 | * создании экземпляра фабрики при помощи фабричного метода. | |
|
|
74 | * @param refs Объект с описанием зависимостей | |
|
|
75 | * @returns Возвращает дескриптор сервиса, в котором указаны необходимые | |
|
|
76 | * зависимости | |
|
|
77 | */ | |
|
|
59 | 78 | wants<X extends DepsMap<S> & Record<keyof R & keyof X, never>>(refs: X): |
|
|
60 | 79 | IDescriptorBuilder<S, T, R & { |
|
|
61 | 80 | [k in keyof X]: Resolve<S, X[k]>; |
|
|
62 | 81 | }, O> |
|
|
63 | 82 | |
|
|
64 | 83 | override<K extends O>(name: K, builder: RegistrationBuilder<S, NonNullable<S[K]>>): this; |
|
|
65 | 84 | override<K extends O>(services: { [name in K]: RegistrationBuilder<S, NonNullable<S[K]>> }): this; |
|
|
66 | 85 | |
|
|
67 | 86 | lifetime(lifetime: "singleton", typeId: string | number | object): this; |
|
|
68 | 87 | lifetime(lifetime: ILifetime<T> | Exclude<ActivationType, "singleton">): this; |
|
|
69 | 88 | |
|
|
89 | /** Указывает функцию для освобождения экземпляра сервиса для случаев, когда | |
|
|
90 | * время жизни привязано к контейнеру. | |
|
|
91 | */ | |
|
|
70 | 92 | cleanup(cb: (item: T) => void): this; |
|
|
71 | 93 | |
|
|
94 | /** | |
|
|
95 | * Регистрирует в контейнере постоянное значение в качестве реализации сервиса. | |
|
|
96 | * | |
|
|
97 | * @param v Экземпляр реализации сервиса. | |
|
|
98 | */ | |
|
|
72 | 99 | value(v: T): void; |
|
|
73 | 100 | } |
|
|
74 | 101 | |
|
|
75 |
export type RegistrationBuilder<S |
|
|
|
102 | export type RegistrationBuilder<S, T> = (d: IDescriptorBuilder<S, T, object, ConfigurableKeys<S>>) => void; | |
|
|
76 | 103 | |
|
|
77 | 104 | export type RegistrationBuildersMap<S extends Configurable<S>, K extends keyof S = keyof S> = { |
|
|
78 | 105 | [k in K]-?: RegistrationBuilder<ContainerServices<S>, NonNullable<S[k]>> |
|
|
79 | 106 | }; |
|
|
80 | 107 | |
|
|
81 |
export interface Descriptor<S |
|
|
|
108 | export interface Descriptor<S, T> { | |
|
|
82 | 109 | activate(context: IActivationContext<S>): T; |
|
|
83 | 110 | } |
|
|
84 | 111 | |
|
|
85 |
export interface IActivationContext<S |
|
|
|
112 | export interface IActivationContext<S> extends ServiceLocator<S> { | |
|
|
86 | 113 | createLifetime<T>(): ILifetime<T>; |
|
|
87 | 114 | |
|
|
88 | 115 | createContainerLifetime<T>(): ILifetime<T>; |
|
|
89 | 116 | } |
|
|
90 | 117 | |
|
|
91 |
export type RegistrationMap<S |
|
|
|
118 | export type RegistrationMap<S, K extends keyof S = keyof S> = { | |
|
|
92 | 119 | [k in K]-?: Descriptor<S, S[k]>; |
|
|
93 | 120 | }; |
|
|
94 | 121 | |
|
|
95 |
export interface ContainerProvided<S |
|
|
|
122 | export interface ContainerProvided<S> { | |
|
|
96 | 123 | container: ServiceLocator<ContainerServices<S>>; |
|
|
97 | 124 | |
|
|
98 | 125 | childContainer: IContainerBuilder<S>; |
|
|
99 | 126 | } |
|
|
100 | 127 | |
|
|
101 |
export type Configurable<S> = { [k in keyof S |
|
|
|
128 | export type Configurable<S> = { [k in keyof S]: k extends ProvidedKeys ? never : S[k]; }; | |
|
|
102 | 129 | |
|
|
103 | 130 | export type ProvidedKeys = keyof ContainerProvided<never>; |
|
|
104 | 131 | |
|
|
105 | export type ContainerServices<S extends Configurable<S>> = S & ContainerProvided<S>; | |
|
|
132 | export type ContainerServices<S> = | |
|
|
133 | { [k in keyof S as k extends ProvidedKeys ? never: k]: S[k] } & | |
|
|
134 | ContainerProvided<S>; | |
|
|
106 | 135 | |
|
|
107 |
export type ConfigurableKeys<S |
|
|
|
136 | export type ConfigurableKeys<S> = Exclude<keyof S, ProvidedKeys>; | |
|
|
108 | 137 | |
|
|
109 |
export type ConfigurableServices<S |
|
|
|
138 | export type ConfigurableServices<S> = Pick<S, ConfigurableKeys<S>>; | |
|
|
110 | 139 | |
|
|
111 |
export type ContainerKeys<S |
|
|
|
140 | export type ContainerKeys<S> = keyof S | ProvidedKeys; | |
|
|
112 | 141 | |
|
|
113 |
export interface ServiceLocator<S |
|
|
|
142 | export interface ServiceLocator<S> { | |
|
|
114 | 143 | resolve<K extends keyof S>(name: K): NonNullable<S[K]>; |
|
|
115 | 144 | resolve<K extends keyof S, T>(name: K, def: T): NonNullable<S[K]> | T; |
|
|
116 | 145 | } |
|
|
117 | 146 | |
|
|
118 | 147 | export interface LifetimeContainer { |
|
|
119 | 148 | createLifetime<T>(): ILifetime<T>; |
|
|
120 | 149 | } |
|
|
121 | 150 | |
|
|
122 |
export interface ServiceContainer<S |
|
|
|
151 | export interface ServiceContainer<S> extends | |
|
|
123 | 152 | ServiceLocator<ContainerServices<S>>, |
|
|
124 | 153 | IDestroyable { |
|
|
125 | 154 | |
|
|
126 | 155 | createChildContainer(): IContainerBuilder<S>; |
|
|
127 | 156 | } |
|
|
128 | 157 | |
|
|
129 |
export interface IContainerBuilder<S |
|
|
|
158 | export interface IContainerBuilder<S> { | |
|
|
130 | 159 | createServiceBuilder<K extends keyof S>(name: K): IDescriptorBuilder<S, NonNullable<S[K]>, object, keyof S>; |
|
|
131 | 160 | |
|
|
132 | 161 | build(): ServiceContainer<S>; |
|
|
133 | 162 | } |
|
|
134 | 163 | |
|
|
135 | 164 | |
|
|
136 | 165 | export type ActivationType = "singleton" | "container" | "hierarchy" | "context" | "call"; |
|
|
137 | 166 | |
|
|
138 | 167 | /** |
|
|
139 | 168 | * Интерфейс для управления жизнью экземпляра объекта. Каждая регистрация имеет |
|
|
140 | 169 | * свой собственный объект `ILifetime`, который создается при первой активации |
|
|
141 | 170 | */ |
|
|
142 | 171 | export interface ILifetime<T> { |
|
|
143 | 172 | /** Проверяет, что уже создан экземпляр объекта */ |
|
|
144 | 173 | has(): boolean; |
|
|
145 | 174 | |
|
|
146 | 175 | get(): T; |
|
|
147 | 176 | |
|
|
148 | 177 | initialize(context: IActivationContext<object>): void; |
|
|
149 | 178 | |
|
|
150 | 179 | store(item: T, cleanup?: (item: T) => void): void; |
|
|
151 | 180 | } |
|
|
152 | 181 | |
|
|
153 | 182 | export type ExtractRequired<T, K extends keyof T = keyof T> = { [p in K as (undefined extends T[p] ? never : p)]-?: T[p] }; |
|
|
154 | 183 | |
| @@ -1,49 +1,49 | |||
|
|
1 | 1 | import { FluentConfiguration } from "./FluentConfiguration"; |
|
|
2 | 2 | import { IDestroyable } from "./interfaces"; |
|
|
3 | 3 | |
|
|
4 |
export function fluent<S |
|
|
|
4 | export function fluent<S = {}>() { | |
|
|
5 | 5 | return new FluentConfiguration<S>(); |
|
|
6 | 6 | } |
|
|
7 | 7 | |
|
|
8 | 8 | export type key = string | number | symbol; |
|
|
9 | 9 | |
|
|
10 | 10 | export const isKey = (v: unknown): v is key => |
|
|
11 | 11 | typeof v === "string" || typeof v === "number" || typeof v === "symbol"; |
|
|
12 | 12 | |
|
|
13 | 13 | export const isString = (v: unknown): v is string => |
|
|
14 | 14 | typeof v === "string"; |
|
|
15 | 15 | |
|
|
16 | 16 | |
|
|
17 | 17 | export const isNotNull = <T>(v: T): v is NonNullable<T> => v !== null && v !== undefined; |
|
|
18 | 18 | |
|
|
19 | 19 | export const each = <T extends object>(obj: T, cb: <X extends Extract<keyof T, string>>(v: NonNullable<T[X]>, k: X) => void) => |
|
|
20 | 20 | (Object.keys(obj) as (Extract<keyof T, string>)[]) |
|
|
21 | 21 | .forEach(k => { |
|
|
22 | 22 | const v = obj[k]; |
|
|
23 | 23 | isNotNull(v) && cb(v, k); |
|
|
24 | 24 | }); |
|
|
25 | 25 | |
|
|
26 | 26 | export const argumentNotNull = (arg: unknown, name: string) => { |
|
|
27 | 27 | if (arg === null || arg === undefined) |
|
|
28 | 28 | throw new Error("The argument " + name + " can't be null or undefined"); |
|
|
29 | 29 | }; |
|
|
30 | 30 | |
|
|
31 | 31 | export const isPromise = <T = unknown>(val: unknown): val is PromiseLike<T> => |
|
|
32 | 32 | isNotNull(val) && typeof (val as PromiseLike<T>).then === "function"; |
|
|
33 | 33 | |
|
|
34 | 34 | export const isDestroyable = (d: unknown): d is IDestroyable => |
|
|
35 | 35 | isNotNull(d) && typeof (d as IDestroyable).destroy === "function"; |
|
|
36 | 36 | |
|
|
37 | 37 | let _nextOid = 0; |
|
|
38 | 38 | const _oid = typeof Symbol === "function" ? |
|
|
39 | 39 | Symbol.for("__implab__oid__") : |
|
|
40 | 40 | "__implab__oid__"; |
|
|
41 | 41 | |
|
|
42 | 42 | type OidSlot = { [k in typeof _oid]?: string }; |
|
|
43 | 43 | |
|
|
44 | 44 | export const oid = <T extends object>(instance: T): string => { |
|
|
45 | 45 | argumentNotNull(instance, "instance"); |
|
|
46 | 46 | const val = (instance as OidSlot)[_oid]; |
|
|
47 | 47 | |
|
|
48 | 48 | return val ? val : ((instance as OidSlot)[_oid] = `oid_${++_nextOid}`); |
|
|
49 | 49 | }; No newline at end of file |
| @@ -1,87 +1,100 | |||
|
|
1 | 1 | /* eslint max-classes-per-file: ["error", 20] */ |
|
|
2 | 2 | import { describe, it } from "mocha"; |
|
|
3 | 3 | import { Container } from "../Container"; |
|
|
4 |
import { Container |
|
|
|
4 | import { ContainerBuilder } from "../ContainerBuilder"; | |
|
|
5 | import { ConfigurableKeys, ContainerProvided, ContainerServices, DepsMap, Refs, Resolver } from "../interfaces"; | |
|
|
5 | 6 | import { fluent } from "../traits"; |
|
|
6 | 7 | |
|
|
7 | 8 | class Foo { |
|
|
8 | 9 | foo = "foo"; |
|
|
9 | 10 | } |
|
|
10 | 11 | |
|
|
11 | 12 | class Bar { |
|
|
12 | 13 | bar = "bar"; |
|
|
13 | 14 | |
|
|
14 | 15 | constructor(foo?: () => Foo) { } |
|
|
15 | 16 | } |
|
|
16 | 17 | |
|
|
17 | 18 | interface Services { |
|
|
18 | 19 | foo: Foo; |
|
|
19 | 20 | |
|
|
20 | 21 | bar?: Bar; |
|
|
21 | 22 | |
|
|
22 | 23 | baz: Foo; |
|
|
24 | ||
|
|
25 | container: string; | |
|
|
23 | 26 | } |
|
|
24 | 27 | |
|
|
25 | 28 | interface ServicesB { |
|
|
26 | 29 | // will give errors |
|
|
27 | 30 | // baz: Bar; |
|
|
28 | 31 | |
|
|
29 | 32 | baz: Foo; |
|
|
30 | 33 | |
|
|
31 | 34 | zoo?: Foo; |
|
|
32 | 35 | } |
|
|
33 | 36 | |
|
|
34 | 37 | declare const resolver: Resolver<Services>; |
|
|
35 | 38 | |
|
|
36 | 39 | const foo = resolver("foo", {lazy: true}); |
|
|
37 | 40 | |
|
|
38 |
const mmap = <X extends DepsMap<Services |
|
|
|
41 | const mmap = <X extends DepsMap<Services>>(m: X) => {}; | |
|
|
42 | ||
|
|
43 | declare const refs: Refs<Services>; | |
|
|
39 | 44 | |
|
|
40 | const refs: Refs<Services> = {name: "bar", default: undefined}; | |
|
|
45 | if (refs && refs.name === "foo") { | |
|
|
46 | refs.default; | |
|
|
47 | } | |
|
|
48 | ||
|
|
49 | declare const x: ContainerServices<Services>; | |
|
|
50 | ||
|
|
51 | x.container.resolve("container"); | |
|
|
52 | ||
|
|
41 | 53 | |
|
|
42 | 54 | mmap({ |
|
|
43 | 55 | fooz: {name: "foo", lazy: false, default: undefined }, |
|
|
44 | 56 | ooz: "bar" |
|
|
45 | 57 | }); |
|
|
46 | 58 | |
|
|
47 | 59 | interface SharedServices { |
|
|
48 | 60 | foo: Foo; |
|
|
49 | 61 | |
|
|
50 | 62 | bar?: Bar; |
|
|
51 | 63 | |
|
|
52 | 64 | baz: Bar; |
|
|
53 | 65 | } |
|
|
54 | 66 | |
|
|
55 | 67 | const config = fluent() |
|
|
56 | 68 | .declare<Services>() |
|
|
57 | 69 | .declare<ServicesB>() |
|
|
58 | 70 | .register({ |
|
|
71 | zoo: it => {}, | |
|
|
59 | 72 | bar: it => it |
|
|
60 | 73 | .lifetime("context") // тип активации, время жизни |
|
|
61 | 74 | .wants({ |
|
|
62 | 75 | zoo: "zoo", // зависимость |
|
|
63 | 76 | bar: "bar", |
|
|
64 | 77 | |
|
|
65 | 78 | $zoo: { name: "foo", lazy: true, } // отложенная активация, |
|
|
66 | 79 | //фабричный метод |
|
|
67 | 80 | }) |
|
|
68 | 81 | .wants({ |
|
|
69 | 82 | zoom: "bar" |
|
|
70 | 83 | }) |
|
|
71 | 84 | .factory(({ $zoo, zoo }) => // фабрика получает объект с именованными зависимостями |
|
|
72 | 85 | // удобно для деструктурирования |
|
|
73 | 86 | new Bar($zoo) // создается экземпляр сервиса |
|
|
74 | 87 | ), |
|
|
75 | 88 | foo: it => it.factory(() => new Foo()), |
|
|
76 | 89 | baz: it => it.value(new Foo()) |
|
|
77 | 90 | }) |
|
|
78 | 91 | .done({}); |
|
|
79 | 92 | |
|
|
80 |
declare const container: Container< |
|
|
|
93 | declare const container: ContainerBuilder<{}>; | |
|
|
81 | 94 | const c2 = config.configure(container); |
|
|
82 | 95 | |
|
|
83 | 96 | c2.resolve("foo"); |
|
|
84 | 97 | |
|
|
85 | 98 | declare const m :ContainerServices<{foo: Foo}>["container"]; |
|
|
86 | 99 | |
|
|
87 | m.resolve("container").resolve("container"); No newline at end of file | |
|
|
100 | m.resolve("container").resolve("container").resolve("foo"); No newline at end of file | |
General Comments 0
You need to be logged in to leave comments.
Login now
