首页 > 解决方案 > 将 nodejs 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")

上面的代码适用于正确的容器配置。但是,解析的函数对象没有类型推断。有没有办法获取类型?

标签: node.jsdependency-injection

解决方案


这不是我自己的原始答案,但我遇到了这个可能对您有帮助的代码沙箱: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;
}

推荐阅读