typescript - 反转打字稿工厂绑定返回联合类型?
问题描述
我正在使用 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 用于工厂?我该如何纠正?
解决方案
我正在猜测为什么以这种方式实现 - 允许在绑定时进行两次柯里化。如果 Factory 不是联合类型,您将无法绑定以下内容:
context => (options) => (destination) => { ...destination based logger... }
但是,正如您刚才提到的,如果您确定您的工厂不会返回闭包,则可以将其转换为所需的类型。您也可以在分配时这样做:
const logger: Logger = referenceContainer.get<interfaces.Factory<Logger>>(TYPES.LoggerFactory)(config.loggerOptions) as Logger;
@inject
尽可能使用装饰器也是一个好主意。我认为由于这是runApp
一个类似于入口点的功能,因此可以使用它。但除此之外,为了获得良好的解耦和可测试性,我们应该使用装饰器。