🦄 2024 独立开发者训练营,一起创业!查看介绍 / 立即报名(剩余10个优惠名额) →

Nest.js:自定义 Provider(文档)

很多时候我们需要直接往 Nest 的 Ioc(Inversion of control)  容器里绑定点东西。比如,一些 constant 值,基于当前环境创建的配置对象,外部库,或者根据一些其它定义的 provider 提前算好的值等等。而且你还可以覆盖实施,比如使用不同的类,需要时还可以使用各种测试替身。

要注意一件非常重要的事情,就是 Nest 会使用 token 来确定依赖。一般这个自动生成的 token 就是类。如果你要创建自定义的 provider,你得自个儿选择一个 token。大部分情况这个 token 都可以使用字符串或 symbol 表示。最好你可以在单独的文件里存储这些 token,比如放在一个 constants.ts 文件里。下面是一些可用的选项。

使用值

定义 constant 值,把外部库放到 Nest 容器里,或者使用 mock 对象替换真实的实施,这些情况都可以用 useValue 这种用法。

import { connection } from './connection';

const connectionProvider = {
  provide: 'CONNECTION',
  userValue: connection,
};

@Module({
  providers: [connectionProvider],
})
export class ApplicationModule {}

上面定义了一个自定义的 provider,使用它的时候可以使用 @Inject 装饰器,这个装饰器的参数就是 provider 的 token 。

@Injectable()
export class CatsRepository {
  constructor(
    @Inject('CONNECTION')
    connection: Connection
  ) {}
}

如果你要覆盖一个默认 provider 的值,比如,你想强制 Nest 使用一个 mock 的 CatsService,用于测试,你可以使用一个已有的 class 作为 token。

import {CatsService} from './cats.service';

const mockCatsService = {};
const catsServiceProvider = {
  provide: CatsService,
  useValue: mockCatsService
}

@Module({
  imports: [CatsModule],
  providers: [catsServiceProvider],
})
export class ApplicationMoulde {}

上面会用 mockCatsService 替换原有的 CatsService。

使用类

useClass 可以根据一些情况使用不同的类。比如,我们有个 abstract ConfigService 类,依赖当前的环境,Nest 会使用不同的配置服务。

const configServiceProvider = {
  provide: ConfigService,
  useClass: process.env.NODE_ENV === 'development'
    ? DevelopmentConfigService
    : ProductionConfigService,
};

@module({
  providers: [configServiceProvider],
})
export class ApplicationModule {}

如果有其它的类依赖 ConfigService,Nest 会注入提供的 DevelopmentConfigService 或者 ProductionConfigService 类的实例。

使用工厂

useFactory 是一种动态创建 provider 的方法。真正的 provider 就是工厂函数返回的值。工厂函数可以依赖一些不同的 provider,也可以是完全独立的。也就是工厂可以接收一些参数,Nest 在实例化的时候会使用这些参数。另外,这个工厂还可以异步返回值。

const connectionFactory = {
  provide: 'CONNECTION',
  useFactory: (optionsProvider: OptionsProvider) => {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@module({
  providers: [connectionFactory],
})
export class ApplicationModule {}

使用已有

useExisting 可以为已有 provider 创建别名。比如 AliasedLoggerService 就是 LoggerService 的别名。

@Injectable()
class LoggerService {}

const loggerAliasProvider = {
  provide: 'AliashedLoggerService',
  useExisting: LoggerService
};

@Module({
  provides: [LoggerService, loggerAliasProvider],
})
export class ApplicationModule {}

导出自定义 Provider

使用 token 或完整的对象都可以导出自定义的 Provider。

使用 token 导出:

const connectionFactory = {
  provide: 'CONNECTION',
  useFactory: (optionsProvider: OptionsProvider) => {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@module({
  providers: [connectionFactory],
  exports: ['CONNECTION']
})
export class ApplicationModule { }

使用完整对象导出:

const connectionFactory = {
  provide: 'CONNECTION',
  useFactory: (optionsProvider: OptionsProvider) => {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@module({
  providers: [connectionFactory],
  exports: [connectionFactory]
})
export class ApplicationModule { }
微信好友

用微信扫描二维码,
加我好友。

微信公众号

用微信扫描二维码,
订阅宁皓网公众号。

240746680

用 QQ 扫描二维码,
加入宁皓网 QQ 群。

统计

15260
分钟
0
你学会了
0%
完成

社会化网络

关于

微信订阅号

扫描微信二维码关注宁皓网,每天进步一点