将Node.js DI容器awilix与类型安全集成

问题描述

我正在考虑将DI容器集成到我现有的nodejs项目之一中。我已经集成了awilix,并且一切正常。

但是,我习惯于在许多地方使用打字稿并使用打字安全性。使用awilix注册依赖项是我无法做到的。

例如我写了高阶函数之类的用例

function createReport(specs){

  const {reportRepostiory} = specs;

  return async (param1: string,param2: string){
    //...
    reportRepostiory.create({//some payload})
  }
  
}

调用函数调用类似


const reportService : any = container.resolve("createReport");
const result = await reportService("1","2")

以上代码在正确的容器配置下可以正常工作。但是,在解析的函数对象上没有类型推断。有没有办法获取类型?

解决方法

这不是我自己的原始答案,但我遇到了这个可能对您有帮助的代码沙箱:https://codesandbox.io/s/qykt1?file=/src/index.ts

如果链接失效,这里是从上述链接中提取的片段。

所有功劳归功于作者 derekrjones (https://codesandbox.io/u/derekrjones)。

import {
  AwilixContainer,asFunction,asValue,asClass,InjectionMode,createContainer,Resolver,ResolveOptions,ContainerOptions
} from "awilix";

/**
 * Container definition base.
 */
interface ContainerDefinition {
  [key: string]: Resolver<unknown>;
}

/**
 * Extracts the type that will be resolved from a resolver.
 */
type ExtractResolverType<T> = T extends Resolver<infer X> ? X : null;

/**
 * Strongly-typed container.
 */
interface TypedAwilixContainer<T extends ContainerDefinition>
  extends Pick<AwilixContainer,Exclude<keyof AwilixContainer,"resolve">> {
  /**
   * Resolves the registration with the given name.
   *
   * @param  {string} name
   * The name of the registration to resolve.
   *
   * @return {*}
   * Whatever was resolved.
   */
  resolve<K extends keyof T>(
    key: K,resolveOptions?: ResolveOptions
  ): ExtractResolverType<T[K]>;
}

/**
 * Wraps `createContainer` and calls `register` on it.
 */
function createTypedContainer<T extends ContainerDefinition>(
  registrations: T,opts?: ContainerOptions
): TypedAwilixContainer<T> {
  return createContainer(opts).register(registrations) as any;
}