如何在NestJS中向类注入接口实现类列表?
问题描述
我定义了如下IParser接口:
export interface IParser { parse(text: string): string }
以及两个实现该接口的类:
@Injectable() export class FirstParser implements IParser { public parse(text: string): string { return text + 'first'; } } @Injectable() export class SecondParser implements IParser { public parse(text: string): string { return text + 'second'; } }
现在我希望在ParserService中注入该接口的实现类列表:
@Injectable() export class ParserService { constructor(private readonly parsers: IParser[]) {} public parse(text: string): string { let parsedText = text; parsedText = this.parsers.reduce((acc: string, result) => { return result.parse(acc); }, parsedText); return parsedText; } }
但在配置ParserServiceModule时,不知道如何配置providers来注入包含FirstParser、SecondParser的数组:
@Module({ providers: [ ParserService, { provide: Array<IParser>, useClass: ???, }, ], }) export class ParserServiceModule {}
请问在NestJS中是否可以实现该需求?具体该如何配置?
解决方案
完全可以实现,核心是利用NestJS的自定义注入令牌和**多提供者(multi: true)**特性——因为TypeScript接口在编译为JavaScript后会被擦除,无法直接作为注入标识使用。
具体配置步骤:
创建注入令牌
定义一个专门的令牌来标识IParser实现集合:import { InjectionToken } from '@nestjs/common'; import { IParser } from './parser.interface'; export const PARSERS = new InjectionToken<IParser[]>('PARSERS');修改
ParserService的注入逻辑
在构造函数中通过@Inject()指定自定义令牌:import { Inject, Injectable } from '@nestjs/common'; import { IParser } from './parser.interface'; import { PARSERS } from './parser.token'; @Injectable() export class ParserService { constructor(@Inject(PARSERS) private readonly parsers: IParser[]) {} public parse(text: string): string { return this.parsers.reduce((acc, parser) => parser.parse(acc), text); } }配置模块的
providers
将每个IParser实现绑定到PARSERS令牌,并设置multi: true,NestJS会自动收集所有绑定实例组成数组:import { Module } from '@nestjs/common'; import { ParserService } from './parser.service'; import { FirstParser } from './first.parser'; import { SecondParser } from './second.parser'; import { PARSERS } from './parser.token'; @Module({ providers: [ ParserService, FirstParser, SecondParser, { provide: PARSERS, useExisting: FirstParser, multi: true, }, { provide: PARSERS, useExisting: SecondParser, multi: true, }, ], }) export class ParserServiceModule {}
简化写法
如果不需要单独导出FirstParser或SecondParser,可以直接在提供者中声明:
@Module({ providers: [ ParserService, { provide: PARSERS, useClass: FirstParser, multi: true, }, { provide: PARSERS, useClass: SecondParser, multi: true, }, ], }) export class ParserServiceModule {}
关键说明
multi: true:告知NestJS当前令牌对应多个实例,会将所有绑定的实例收集为数组注入。- 自定义令牌:解决TypeScript接口无法作为注入标识的问题——接口仅存在于编译阶段,运行时会被擦除,而
InjectionToken是运行时可识别的对象。
内容的提问来源于stack exchange,提问作者yairabr
相关产品推荐
相关产品推荐

