type ServiceApiContract = Record<string, ServiceMethod>;
type ServiceDependencies = Record<string, any>;
type ServiceMethod<
Args extends any[] = any[],
Return extends unknown = unknown
> = (...args: Args) => Return;
interface ServiceMethodFactory<
Deps extends ServiceDependencies = ServiceDependencies,
Args extends any[] = any[],
Return extends unknown = unknown
> {
(deps: Deps): ServiceMethod<Args, Return>;
}
type Service<ApiContract extends ServiceApiContract = ServiceApiContract> =
ApiContract;
interface ServiceFactory<
ApiContract extends ServiceApiContract,
ServiceDeps extends ServiceDependencies = ServiceDependencies
> {
(deps: ServiceDeps): Service<ApiContract>;
}
function withDependencies<
ApiContract extends ServiceApiContract,
Deps extends ServiceDependencies = ServiceDependencies,
InjectableMethods extends Record<string, ServiceMethodFactory<Deps>> = Record<
string,
ServiceMethodFactory<Deps>
>
>(
dependencies: Deps,
injectableMethods: InjectableMethods
): Service<ApiContract> {
const methodsEntries = Object.entries(injectableMethods);
const service = methodsEntries.reduce((apiContractAcc, [name, factoryFn]) => {
apiContractAcc = {
...apiContractAcc,
[name]: factoryFn(dependencies),
};
return apiContractAcc;
}, {} as Service<ApiContract>);
return service;
}