首页 > 解决方案 > 反转打字稿工厂绑定返回联合类型?

问题描述

我正在使用 inversify v4.13.0 和 Typescript,这两个我都是新手。

我有一个Logger界面:

interface Logger {
  log(level: string, message: string, meta?: any): void;
}

类型文件:

const TYPES = {
  Config: Symbol.for('Config'),
  LoggerFactory: Symbol.for('Factory<Logger>')
};

和一些绑定,包括我有问题的记录器工厂绑定,它也将配置对象作为参数:

referenceContainer.bind<Config>(TYPES.Config).to(Config);

referenceContainer.bind<interfaces.Factory<Logger>>(TYPES.LoggerFactory).toFactory<Logger>(
  (context: interfaces.Context) => {
    return (options: PrefixedLoggerOptions = {}): Logger => {
      // return an object that implements Logger
      return PrefixedLoggerFactory(options);
    };
  });

然后我尝试使用我的记录器:

async function runApp() {
  const config = referenceContainer.get<Config>(TYPES.Config);
  const logger = referenceContainer.get<interfaces.Factory<Logger>>(TYPES.LoggerFactory)(config.loggerOptions);

  // **** error: logger has no 'log' property ****
  logger.log('info', 'am I a logger? nope!');

  // but this works
  (logger as Logger).log('info', 'am I a logger? yep!');
}

(async () => {
  await runApp();
})();

如果我尝试使用 Logger 而不进行强制转换,我会看到此错误:

error TS2339: Property 'log' does not exist on type 'Logger | ((...args: any[]) => Logger)'.
Property 'log' does not exist on type '(...args: any[]) => Logger'.

工厂似乎正在返回一个联合返回的自身类型——工厂函数(奇怪???)和记录器。

我检查了 typedef,这似乎是正确的,尽管我不明白这是如何工作的。从类型定义:

type Factory<T> = (...args: any[]) => (((...args: any[]) => T) | T);

我是否错误地将 inversify 用于工厂?我该如何纠正?

标签: typescriptinversifyjs

解决方案


我正在猜测为什么以这种方式实现 - 允许在绑定时进行两次柯里化。如果 Factory 不是联合类型,您将无法绑定以下内容:

context => (options) => (destination) => { ...destination based logger... }

但是,正如您刚才提到的,如果您确定您的工厂不会返回闭包,则可以将其转换为所需的类型。您也可以在分配时这样做:

const logger: Logger = referenceContainer.get<interfaces.Factory<Logger>>(TYPES.LoggerFactory)(config.loggerOptions) as Logger;

@inject尽可能使用装饰器也是一个好主意。我认为由于这是runApp一个类似于入口点的功能,因此可以使用它。但除此之外,为了获得良好的解耦和可测试性,我们应该使用装饰器。


推荐阅读