Интеграция nodejs DI container awilix с безопасностью типов

#node.js #dependency-injection

#node.js #внедрение зависимостей

Вопрос:

Я рассматриваю возможность интеграции контейнера DI в один из моих существующих проектов nodejs. Я интегрировал awilix, и все работает так, как ожидалось.

Тем не менее, я привык к typescript и использую безопасность типов во многих частях. Это одна вещь, которую я не могу получить при регистрации зависимостей с помощью 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")

  

Приведенный выше код прекрасно работает при правильной конфигурации контейнера. Однако для разрешенного объекта функции нет вывода типа. Есть ли какой-нибудь способ получить типы?

Ответ №1:

Это не мой собственный оригинальный ответ, но я наткнулся на эту кодовую песочницу, которая может вам помочь: https://codesandbox.io/s/qykt1?file=/src/index.ts .

На случай, если ссылка исчезнет, вот фрагмент, извлеченный из приведенной выше ссылки.

Вся заслуга принадлежит автору, дерекрионесу (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;
}