@injectable-ts/core
Version:
Purely-functional strictly-typed IoC/DI for TypeScript
62 lines (61 loc) • 3.96 kB
TypeScript
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 {};