我有一个动态模块EmailModule:

@Injectable()
export class EmailSender {}

@Module({})
export class EmailModule {
  static forRoot(options: { smtpHost: string; smtpPassword: string }): DynamicModule {
    return {
      module: EmailModule,
      providers: [EmailSender,],
      exports: [EmailSender,],
    };
  }
}

还有MainModule,它包含CatModule.

@Injectable()
export class CatService {
  constructor(emailSender: EmailSender) {}
}

@Module({
  imports: [
    EmailModule,
  ],
  providers: [CatService,],
  exports: [CatService,],
})
export class CatModule {}

@Module({
  imports: [
    EmailModule.forRoot({
      smtpHost: 'localhost',
      smtpPassword: 'password',
    }),
    CatModule,
  ],
})
export class MainModule {}

此代码不起作用,因为CatService无法解析EmailSender.我必须在CatModule中导入EmailModule.forRoot({host, password}).

然而,我不想这样做.想象一下,我有DogModule、HorseModule、BirdModule、CowModule.我不想写这个长版本,到处都是.forRoot({...})个.我正在寻找一种解决方案,允许我在主模块中使用.forRoot({...}),并在所有子模块中简单地导入EmailModule.

我确信这是可能的,因为这正是nestjs ConfigModule的工作方式.如果我用ConfigModule替换EmailModule,一切都会正常工作!

@Injectable()
export class CatService {
  constructor(configService: ConfigService) {}
}

@Module({
  imports: [
    ConfigModule,
  ],
  providers: [CatService,],
  exports: [CatService,],
})
export class CatModule {}

@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: '../.env',
    }),
    CatModule,
  ],
})
export class MainModule {}

我不明白为什么它可以与ConfigModule一起工作,但不能与EmailModule一起工作.这个模块有什么特别之处?

推荐答案

您有3种解决方案:

  • 在您的邮箱配置中使用"global:true"(如果您只想导入此模块一次并在每个模块中使用它,则可能非常有用):

@Injectable()
export class EmailSender {}

@Module({})
export class EmailModule {
  static forRoot(options: { smtpHost: string; smtpPassword: string }): DynamicModule {
    return {
      module: EmailModule,
      global: true,
      providers: [EmailSender,],
      exports: [EmailSender,],
    };
  }
}

  • 混合使用模块和动态模块:EmailModule.forRoot()和EmailModule,并控制所有导入:

@Injectable()
export class EmailSender {}

@Module({ 
    providers: [
      EmailSender,
      {
          provide: 'CONFIG what ever',
          useValue: dbConfig || EmailModule.emailOptions
        }
    ],
    exports: [EmailSender,]
})
export class EmailModule {

  private static emailOptions = {};
  
  static forRoot(options: { smtpHost: string; smtpPassword: string }): DynamicModule {
  this.emailOptions = options;
   
   return {
      module: EmailModule,
    };
  }
}

@Injectable()
export class CatService {
  constructor(emailSender: EmailSender) {}
}

@Module({
  imports: [
    EmailModule,
  ],
  providers: [
    CatService],
  exports: [CatService,],
})
export class CatModule {}

@Module({
  imports: [
    EmailModule.forRoot({
      smtpHost: 'localhost',
      smtpPassword: 'password',
    }),
    CatModule,
  ],
})
export class MainModule {}

  • 仅使用动态模块:EmailModule.forRoot()和EmailModule.forFeature()(同时控制所有导入):

@Injectable()
export class EmailSender {}

@Module({ })
export class EmailModule {

  private static emailOptions = {};
  
  static forRoot(options: { smtpHost: string; smtpPassword: string }): DynamicModule {
    this.emailOptions = options;
   
    return EmailModule.forFeature();
  }
  
  static forFeature(options?): DynamicModule {
      return {
        module: EmailModule,
        providers: [
        EmailSender,
        {
          provide: 'CONFIG what ever',
          useValue: options || EmailModule.emailOptions
        }
    ],
    exports: [EmailSender,]
    };
  }
}

@Injectable()
export class CatService {
  constructor(emailSender: EmailSender) {}
}

@Module({
  imports: [
    EmailModule.forFeature(),
  ],
  providers: [
    CatService],
  exports: [CatService,],
})
export class CatModule {}

@Module({
  imports: [
    EmailModule.forRoot({
      smtpHost: 'localhost',
      smtpPassword: 'password',
    }),
    CatModule,
  ],
})
export class MainModule {}

请注意,对于两个最终解决方案,您可以更好地控制您的进口,但进口顺序很重要.

这是行不通的:

@Module({
  imports: [
    CatModule,
    EmailModule.forRoot({
      smtpHost: 'localhost',
      smtpPassword: 'password',
    })
  ],
})
export class MainModule {}

Typescript相关问答推荐

从两个用点隔开的对象键生成字符串类型

当两个参数具有相同的通用类型时,如果没有第一个参数,则递减约束默认会导致第二个参数的错误推断

为什么TypScript对条件函数类型和仅具有条件返回类型的相同函数类型的处理方式不同?

推断类型

无需刷新即可让现场访客逆变

React router 6.22.3不只是在生产模式下显示,为什么?

当使用`type B = A`时,B的类型显示为A.为什么当`type B = A时显示为`any `|用A代替?

在泛型类型中对子代执行递归时出错

泛型函数中输入参数类型的推断问题

类型TTextKey不能用于索引类型 ;TOption

如何缩小函数的返回类型?

如何将对象数组中的键映射到另一种对象类型的键?

在类型脚本中将泛型字符串数组转换为字符串字母并集

如何从对象或类动态生成类型

TypeScrip:使用Cypress测试包含插槽的Vue3组件

任何导航器都未处理有效负载为";params";:{";roomId";:";...";}}的导航操作

为什么受歧视的unions 在一种情况下运作良好,但在另一种非常类似的情况下却不起作用?

Typescript不允许在数组中使用联合类型

如何为对象数组中的每个条目推断不同的泛型

从泛型对象数组构造映射类型