@thaitype/ioctopus
Version:
A simple IoC container for JavaScript and TypeScript for classes and functions.
103 lines (96 loc) • 5.13 kB
TypeScript
declare function createServiceRegistry<KeyMap extends Record<string, unknown> = {}>(): ServiceRegistry<KeyMap>;
/**
Service Registry is a design pattern that allows you to define services in a single place.
*/
declare class ServiceRegistry<KeyMap extends Record<string, unknown> = {}> {
keyMap: KeyMap;
define<OutputType, Key extends string>(key: Key, _identifier?: unknown): ServiceBinder<OutputType, Key, KeyMap>;
get(key: keyof KeyMap): symbol;
}
declare class ServiceBinder<Service, Key extends string, KeyMap extends Record<string, unknown>> {
private readonly serviceRegistry;
private readonly key;
constructor(serviceRegistry: ServiceRegistry<KeyMap>, key: Key);
mapTo<NewService extends Service>(): ServiceRegistry<KeyMap & Record<Key, NewService>>;
}
type DependencyKey = symbol | string;
type DependencyKeyType<T extends Record<string, unknown> = {}> = keyof T;
type AnyFunction = (...args: any) => any;
type AnyClass<Return = any> = new (...args: any) => Return;
type ModuleKey = symbol | string;
interface DependencyObject {
[key: string]: DependencyKey;
}
type DependencyArray = DependencyKey[];
type DependencyArrayType<DependenciesTuple extends any[], Services extends Record<string, unknown> = {}> = ToKeysTuple<Services, DependenciesTuple>;
type DependencyObjectType<Dependencies extends Record<string, unknown>, Services extends Record<string, unknown> = {}> = ToKeysObject<Services, Dependencies>;
type Scope = 'singleton' | 'transient' | 'scoped';
interface Bindable<Services extends Record<string, unknown> = {}> {
bind<Key extends DependencyKeyType<Services>>(key: Key): {
toValue: (value: Services[Key]) => void;
toFunction: (fn: CallableFunction) => void;
toHigherOrderFunction: <Fn extends AnyFunction>(fn: Fn, dependencies?: DependencyArrayType<Parameters<Fn>, Services> | DependencyObjectType<Parameters<Fn>[0], Services>, scope?: Scope) => void;
toCurry: <Fn extends AnyFunction>(fn: Fn, dependencies?: DependencyArrayType<Parameters<Fn>, Services> | DependencyObjectType<Parameters<Fn>[0], Services>, scope?: Scope) => void;
toFactory: (factory: CallableFunction, scope?: Scope) => void;
toClass: <Class extends AnyClass>(constructor: Class, dependencies?: DependencyArrayType<ConstructorParameters<Class>, Services> | DependencyObjectType<ConstructorParameters<Class>[0], Services>, scope?: Scope) => void;
};
}
interface Container<Services extends Record<string, unknown> = {}> extends Bindable<Services> {
load(moduleKey: ModuleKey, module: Module<Services>): void;
get<Key extends DependencyKeyType<Services>>(key: Key): Services[Key];
unload(key: ModuleKey): void;
runInScope<T>(callback: () => T): T;
}
interface Module<Services extends Record<string, unknown> = {}> extends Bindable<Services> {
bindings: Map<DependencyKey, Binding>;
}
interface InjectionTokens {
[key: string]: DependencyKey;
}
type ResolveFunction = (dep: DependencyKey) => unknown;
interface Binding {
factory: (resolve: (key: DependencyKey) => unknown) => unknown;
scope: Scope;
}
/**
* Extracts the keys of a type that are of a specific value
*
* @example
* type MyType = {
* a: Cat,
* b: Dog,
* c: Ant,
* }
*
* type Result = FindKeyByValue<MyType, 'a'> // Cat
*/
type FindKeyByValue<T extends Record<string, unknown>, V> = {
[K in keyof T]: T[K] extends V ? K : never;
}[keyof T];
/**
* Extracts the keys of a type that are of a specific value
*
* @example
* type Output = ToKeysTuple<{ a: string, b: number }, [string, number]>;
*
* // Output = ['a', 'b']
*/
type ToKeysTuple<Map extends Record<string, unknown>, T extends any[]> = {
[K in keyof T]: FindKeyByValue<Map, T[K]>;
};
/**
* Extracts the keys of a type that are of a specific value and returns an object
*
* @example
* type Output = ToKeysObject<{ dep1: string, dep2: string, c: { name: string } }, { dep1: string, dep2: string }>;
*
* // Output = { dep1: 'dep1', dep2: 'dep1' | 'dep2' }
*/
type ToKeysObject<Map extends Record<string, unknown>, T extends Record<string, unknown>> = {
[K in keyof T]: FindKeyByValue<Map, T[K]>;
};
type ExtractServiceRegistryType<T> = T extends ServiceRegistry<infer Services> ? Services : never;
type ExtractServiceRegistryKeys<T> = keyof ExtractServiceRegistryType<T>;
declare function createContainer<Services extends Record<string, unknown> = {}>(serviceRegistry: ServiceRegistry<Services>): Container<Services>;
declare function createModule<Services extends Record<string, unknown> = {}>(serviceRegistry: ServiceRegistry<Services>): Module<Services>;
export { type AnyClass, type AnyFunction, type Binding, type Container, type DependencyArray, type DependencyArrayType, type DependencyKey, type DependencyKeyType, type DependencyObject, type DependencyObjectType, type ExtractServiceRegistryKeys, type ExtractServiceRegistryType, type FindKeyByValue, type InjectionTokens, type Module, type ModuleKey, type ResolveFunction, type Scope, ServiceRegistry, type ToKeysObject, type ToKeysTuple, createContainer, createModule, createServiceRegistry };