William Nemenchainitial commit
86fb32e9/11/2022, 1:13:39 AM
.ts
TypeScript
(application/typescript)
// TODO: extract the services things into its own package

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>
  >
  //InjectedMethods extends {
  //  [K in keyof InjectableMethods]: ReturnType<InjectableMethods[K]>;
  //} = { [K in keyof InjectableMethods]: ReturnType<InjectableMethods[K]> }
>(
  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;
}