UNPKG

@injectable-ts/core

Version:

Purely-functional strictly-typed IoC/DI for TypeScript

62 lines (61 loc) 3.96 kB
import { Merge, NoInfer, UnionToIntersection } from './utils'; export interface UnknownDependencyTree { readonly name: PropertyKey | never; readonly type: unknown; readonly children: readonly UnknownDependencyTree[]; readonly optional: boolean; } type PickRequired<DependencyTree extends UnknownDependencyTree> = { readonly [Name in DependencyTree['name'] as DependencyTree['optional'] extends true ? never : Name]: DependencyTree['type']; }; type PickOptional<DependencyTree extends UnknownDependencyTree> = { readonly [Name in DependencyTree['name'] as DependencyTree['optional'] extends true ? Name : never]?: DependencyTree['type']; }; export type Flatten<Tree> = Tree extends UnknownDependencyTree ? PickRequired<Tree> & PickOptional<Tree> & UnionToIntersection<{ readonly [Index in keyof Tree['children']]: Flatten<Tree['children'][Index]>; }[number]> : never; export interface InjectableWithoutName<Tree extends UnknownDependencyTree, Value> { (tree: Flatten<NoInfer<Tree>>): Value; } export interface InjectableWithName<Tree extends UnknownDependencyTree, Value> { (tree: Flatten<NoInfer<Tree>>): Value; readonly key: Tree['name']; } export type Injectable<Tree extends UnknownDependencyTree, Value> = InjectableWithoutName<Tree, Value> | InjectableWithName<Tree, Value>; export type InjectableValue<Target> = Target extends Injectable<UnknownDependencyTree, infer Value> ? Value : never; export type InjectableDependencyTree<Target> = Target extends Injectable<infer Tree, unknown> ? Tree : never; export type InjectableDependencies<Target> = Merge<Flatten<InjectableDependencyTree<Target>>>; type MapInjectablesToValues<Targets> = { readonly [Index in keyof Targets]: InjectableValue<Targets[Index]>; }; export interface DependencyWithoutName<Result, Children> { readonly name: never; readonly type: Result; readonly optional: false; readonly children: Children; } export interface DependencyWithName<Name, Result, Children> { readonly name: Name; readonly type: Result; readonly optional: true; readonly children: Children; } export declare function injectable<Name extends PropertyKey, Result>(name: Name, project: () => Result): InjectableWithName<DependencyWithName<Name, Result, []>, Result>; export declare function injectable<Result>(project: () => Result): InjectableWithoutName<DependencyWithoutName<Result, []>, Result>; export declare function injectable<Inputs extends Record<PropertyKey, Injectable<UnknownDependencyTree, unknown>>, Result>(inputs: Inputs, project: (values: { readonly [Key in keyof Inputs]: InjectableValue<Inputs[Key]>; }) => Result): InjectableWithoutName<DependencyWithoutName<Result, { [Key in keyof Inputs]: InjectableDependencyTree<Inputs[Key]>; }[keyof Inputs][]>, Result>; export declare function injectable<Name extends PropertyKey, Inputs extends Record<PropertyKey, Injectable<UnknownDependencyTree, unknown>>, Result>(name: Name, inputs: Inputs, project: (values: { readonly [Key in keyof Inputs]: InjectableValue<Inputs[Key]>; }) => Result): InjectableWithName<DependencyWithName<Name, Result, { [Key in keyof Inputs]: InjectableDependencyTree<Inputs[Key]>; }[keyof Inputs][]>, Result>; export declare function injectable<Name extends PropertyKey, Inputs extends readonly Injectable<UnknownDependencyTree, unknown>[], Result>(name: Name, ...args: [...Inputs, (...values: MapInjectablesToValues<Inputs>) => Result]): InjectableWithName<DependencyWithName<Name, Result, { readonly [Index in keyof Inputs]: InjectableDependencyTree<Inputs[Index]>; }>, Result>; export declare function injectable<Inputs extends readonly Injectable<UnknownDependencyTree, unknown>[], Result>(...args: [...Inputs, (...values: MapInjectablesToValues<Inputs>) => Result]): InjectableWithoutName<DependencyWithoutName<Result, { readonly [Index in keyof Inputs]: InjectableDependencyTree<Inputs[Index]>; }>, Result>; export {};