@evyweb/ioctopus
Version:
A simple IoC container for JavaScript and TypeScript for classes and functions.
92 lines (88 loc) • 4.96 kB
TypeScript
type DependencyKey = symbol | string;
type ModuleKey = symbol | string;
interface DependencyObject {
[key: string]: DependencyKey;
}
type DependencyArray = DependencyKey[];
type Scope = 'singleton' | 'transient' | 'scoped';
interface DefaultRegistry {
[key: string]: unknown;
}
type RegistryKey<TRegistry> = Extract<keyof TRegistry, DependencyKey>;
type IncompatibleOverride<K extends PropertyKey, Expected, Provided> = {
__error: 'Incompatible override type for registry key';
key: K;
expected: Expected;
provided: Provided;
};
type CompatibleKey<TRegistry, TOverride> = [TOverride] extends [never] ? RegistryKey<TRegistry> : {
[K in RegistryKey<TRegistry>]: TOverride extends TRegistry[K] ? K : IncompatibleOverride<K, TRegistry[K], TOverride>;
}[RegistryKey<TRegistry>];
interface Bindable {
bind(key: DependencyKey): {
toValue: (value: unknown) => void;
toFunction: (fn: CallableFunction) => void;
toHigherOrderFunction: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
toCurry: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
toFactory: (factory: CallableFunction, scope?: Scope) => void;
toClass: <C>(constructor: new (...args: any[]) => C, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
};
}
interface TypedBindable<TRegistry> {
bind<K extends RegistryKey<TRegistry>>(key: K): {
toValue: (value: TRegistry[K]) => void;
toFunction: (fn: CallableFunction) => void;
toHigherOrderFunction: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
toCurry: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
toFactory: (factory: CallableFunction, scope?: Scope) => void;
toClass: <C>(constructor: new (...args: any[]) => C, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
};
bind(key: DependencyKey): {
toValue: (value: unknown) => void;
toFunction: (fn: CallableFunction) => void;
toHigherOrderFunction: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
toCurry: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
toFactory: (factory: CallableFunction, scope?: Scope) => void;
toClass: <C>(constructor: new (...args: any[]) => C, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
};
}
interface Container extends Bindable {
load(moduleKey: ModuleKey, module: Module): void;
get<T>(key: DependencyKey): T;
unload(key: ModuleKey): void;
runInScope<T>(callback: () => T): T;
}
interface TypedContainer<TRegistry> {
bind<K extends keyof TRegistry & DependencyKey>(key: K): {
toValue: (value: TRegistry[K]) => void;
toFunction: (fn: TRegistry[K] extends CallableFunction ? TRegistry[K] : never) => void;
toHigherOrderFunction: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
toCurry: (fn: CallableFunction, dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
toFactory: (factory: (resolve: (key: DependencyKey) => unknown) => TRegistry[K], scope?: Scope) => void;
toClass: (constructor: new (...args: any[]) => TRegistry[K], dependencies?: DependencyArray | DependencyObject, scope?: Scope) => void;
};
load<TModuleRegistry>(moduleKey: ModuleKey, module: TypedModule<TModuleRegistry>): void;
load(moduleKey: ModuleKey, module: Module): void;
get<TOverride = never, K extends CompatibleKey<TRegistry, TOverride> = CompatibleKey<TRegistry, TOverride>>(key: K): [TOverride] extends [never] ? TRegistry[K & keyof TRegistry] : TOverride;
unload(key: ModuleKey): void;
runInScope<T>(callback: () => T): T;
}
interface Module extends Bindable {
bindings: Map<DependencyKey, Binding>;
}
interface TypedModule<TRegistry> extends TypedBindable<TRegistry> {
bindings: Map<DependencyKey, Binding>;
}
interface InjectionTokens {
[key: string]: DependencyKey;
}
type ResolveFunction = (dep: DependencyKey) => unknown;
interface Binding {
factory: (resolve: (key: DependencyKey) => unknown) => unknown;
scope: Scope;
}
declare function createContainer(): Container;
declare function createContainer<TRegistry>(): TypedContainer<TRegistry>;
declare function createModule(): Module;
declare function createModule<TRegistry>(): TypedModule<TRegistry>;
export { type Binding, type Container, type DefaultRegistry, type DependencyArray, type DependencyKey, type DependencyObject, type InjectionTokens, type Module, type ModuleKey, type ResolveFunction, type Scope, type TypedContainer, type TypedModule, createContainer, createModule };