如何从带有接口的 Nestjs 中的自定义配置文件中获取值?

问题描述

我试图在“config.ts”中的一个文件中设置我的所有配置,将其加载到 ConfigService,然后使用配置接口从中获取值。 所以这是我的 config.ts,其中包含来自我的 .env 文件和静态变量的 ENV 变量。

更新:Made repo with this example

import { Config } from './config.interface';

const config: Config = {
  typeorm: {
    type: 'postgres',host: process.env.DB_HOST,port: +process.env.DB_PORT,username: process.env.DB_USERNAME,password: process.env.DB_PASSWORD,database: process.env.DB_NAME,synchronize: process.env.NODE_ENV !== 'prod',logging: true,entities: [User,RefreshToken],},};

export default () => config;

这是我的界面:

export interface Config {
  typeorm: TypeOrmConfig;
}

export interface TypeOrmConfig {
  type: string;
  host: string;
  port: number;
  username: string;
  password: string;
  database: string;
  synchronize: boolean;
  logging: boolean;
  entities: any[];
}

config 加载到 app.module.ts 中的 ConfigModule

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,envFilePath: '.dev.env',load: [config],}),

例如,我想使用此设置来设置我的 TypeOrmModule。 基于 nestJs 文档

TypeOrmModule.forRootAsync({
      imports: [ConfigModule],useFactory: async (configService: ConfigService) => {
        const config = configService.get<TypeOrmConfig>('typeorm');
        console.log(config);
        return {
          type: config.type,host: config.host,port: +config.port,username: config.username,password: config.password,database: config.database,synchronize: config.synchronize,logging: config.logging,entities: config.entities,};
      },inject: [ConfigService],

问题来了。来自 config 的静态值没问题,但我所有的 ENV 变量都未定义。这是 console.log 输出

{
  type: 'postgres',host: undefined,port: NaN,username: undefined,password: undefined,database: undefined,synchronize: true,entities: [
    [class User extends CoreEntity],[class RefreshToken extends CoreEntity]
  ]
}

我不明白未定义的 ENV 变量有什么问题 我将不胜感激任何解释和帮助

解决方法

简而言之,NestJS 要求您为您尝试在此处访问的自定义配置“typeorm”定义一个命名空间(请参阅 Configuration Namespace):

const config = configService.get<TypeOrmConfig>('typeorm');

这意味着您必须使用 registerAs 函数来创建您的命名空间:

import { registerAs } from '@nestjs/config';
import { TypeOrmConfig } from './config.interface';

export default registerAs(
  'typeorm',(): TypeOrmConfig => ({
    type: 'postgres',host: process.env.DB_HOST,port: +process.env.DB_PORT,username: process.env.DB_USERNAME,password: process.env.DB_PASSWORD,database: process.env.DB_NAME,synchronize: process.env.NODE_ENV !== 'prod',logging: true,entities: [],}),);

这会解决问题。但是,我们可以改进这一点。

不是为 TypeORM 配置定义自己的接口,而是可以使用和/或扩展现有接口以减少样板代码(下面我提到 ConnectionOptions,但 TypeOrmModuleOptions 可能更合适,具体取决于根据您的配置需要)。我还建议为环境变量提供后备值:

import { registerAs } from '@nestjs/config';
import { ConnectionOptions } from 'typeorm';

const CONNECTION_TYPE = 'postgres';

export default registerAs(
  'typeorm',(): ConnectionOptions => ({
    type: CONNECTION_TYPE,host: process.env.DB_HOST || 'default_value',port: +process.env.DB_PORT || 3000,username: process.env.DB_USERNAME || 'default_value',password: process.env.DB_PASSWORD || 'default_value',database: process.env.DB_NAME || 'default_value',);  

此外,无需再次为 TypeOrmModule 显式分配配置值,您只需:

TypeOrmModule.forRootAsync({
  imports: [ConfigModule],useFactory: async (configService: ConfigService) =>
    await configService.get('typeorm'),inject: [ConfigService],

作为个人风格,我喜欢创建配置枚举来包含配置名称以防止拼写错误。考虑一下:

export enum ConfigEnum {
  TYPEORM = 'typeorm',}

TypeOrmModule.forRootAsync({
  imports: [ConfigModule],useFactory: async (configService: ConfigService) =>
    await configService.get<Promise<TypeOrmModuleOptions>>(
      ConfigEnum.TYPEORM,),})

Async / Await 模式在这里也是多余的,因为我们实际上并没有执行任何异步操作,所以这也能正常工作:

TypeOrmModule.forRootAsync({
  imports: [ConfigModule],useFactory: (configService: ConfigService) =>
    configService.get<TypeOrmModuleOptions>(ConfigEnum.TYPEORM),})

欢迎使用 StackOverflow!

附言。我已提出拉取请求,请参阅 https://github.com/JustDenP/nest-config/pull/1

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...