如何在打字稿中使用节点配置?

How to use node-config in typescript?

安装 node-config@types/config 后:

yarn add config
yarn add --dev @types/config

并按照 lorenwest/node-config 中所述添加配置:

// default.ts
export default {
  server: {
    port: 4000,
  },
  logLevel: 'error',
};

当我尝试在我的应用程序中使用时:

import config from 'config';

console.log(config.server);

我收到错误:

src/app.ts(19,53): error TS2339: Property 'server' does not exist on type 'IConfig'.

config.get 实用程序可用于获取配置值,如下所示:

import config from 'config';

const port: number = config.get('server.port');

我用的是IConfig接口,所以可以先设置config路径:

import { IConfig } from 'config';

export function dosomething() {

  process.env["NODE_CONFIG_DIR"] = 'path to config dir';

  //using get
  const config: IConfig = require("config");
  const port = config.get('server.port');
  console.log('port', port);

  //using custom schema
  const config2: { server: { port: number } } = require("config");
  console.log('config2.server.port', config2.server.port);

}

//port 4000
//config2.server.port 4000

从以前开始,我仍然遇到 config 无法从 default.ts 中找到 server 密钥的问题。

下面是我如何使用 npm 配置模块。已将 export default { 更新为 export =

// default.ts
export = {
  server: {
    port: 4000,
  },
  logLevel: 'error',
};

应用内使用情况[相同]:

import config from 'config';

console.log(config.get('server'));

使用这个 "import * as config from 'config';" 而不是 "import config from 'config';"

    import * as config from 'config';

    const port = config.get('server.port');
    console.log('port', port);
    // port 4000

config/development.json

    {
      "server": {
          "port": 4000
      }
    }

并设置NODE_ENV=发展

 export NODE_ENV=development

注意:如果您使用默认

,则无需设置此 NODE_ENV

我采用了一种稍微不同的方法 - 在 JavaScript 中定义变量,并在 TypeScript 中访问它们。

使用以下文件夹结构:

├── config
│   ├── custom-environment-variables.js
│   ├── default.js
│   ├── development.js
│   └── production.js
└── server
    ├── config.ts
    └── main.ts

我在根 config/ 文件夹中定义配置。例如:

// config/default.js
module.exports = {
  cache: false,
  port: undefined  // Setting to undefined ensures the environment config must define it
};

// config/development.js
module.exports = {
  port: '3000'
}

// config/production.js
module.exports = {
  cache: true
}

// config/custom-environment-variables.js
module.exports = {
  port: 'PORT'
}

现在,在 TypeScript 领域,我定义了一个接口来提供更好的自动完成和文档,并编写了一些桥接代码以将配置从 node-config 拉入我的配置映射:

// server/config.ts
import nodeConfig from 'config';

interface Config {
  /** Whether assets should be cached or not. */
  cache: boolean;

  /** The port that the express server should bind to. */
  port: string;
}

const config: Config = {
  cache: nodeConfig.get<boolean>('cache'),
  port: nodeConfig.get<string>('port')
};

export default config;

最后,我现在可以在任何 TypeScript 代码中导入和使用我的配置变量。

// server/main.ts
import express from 'express';
import config from './config';

const { port } = config;

const app = express();

app.listen(port);

这种方法有以下好处:

  • 我们可以使用 node-config 提供的丰富且久经考验的功能,而无需重新发明轮子
  • 我们有一个强类型的、有据可查的配置映射,可以从我们的 TS 代码中的任何地方导入和使用它

您可以使用 any return 类型。

const serverConfig: any = config.get('server');

我可以使这项工作的唯一方法是卸载 @types/config 并修改类型定义以包含我的配置文件。

config.d.ts

    declare module 'config' {
    
      // Importing my config files
      import dev from '#config/development.json'
      import test from '#config/test.json'
      import prod from '#config/production.json'
    
      // Creating a union of my config
      type Config = typeof dev | typeof test | typeof prod
    
      var c: c.IConfig;
    
      namespace c {
    
        // see https://github.com/lorenwest/node-config/wiki/Using-Config-Utilities
        interface IUtil {
            // Extend an object (and any object it contains) with one or more objects (and objects contained in them).
            extendDeep(mergeInto: any, mergeFrom: any, depth?: number): any;
    
            // Return a deep copy of the specified object.
            cloneDeep(copyFrom: any, depth?: number): any;
    
            // Return true if two objects have equal contents.
            equalsDeep(object1: any, object2: any, dept?: number): boolean;
    
            // Returns an object containing all elements that differ between two objects.
            diffDeep(object1: any, object2: any, depth?: number): any;
    
            // Make a javascript object property immutable (assuring it cannot be changed from the current value).
            makeImmutable(object: any, propertyName?: string, propertyValue?: string): any;
    
            // Make an object property hidden so it doesn't appear when enumerating elements of the object.
            makeHidden(object: any, propertyName: string, propertyValue?: string): any;
    
            // Get the current value of a config environment variable
            getEnv(varName: string): string;
    
            // Return the config for the project based on directory param if not directory then return default one (config).
            loadFileConfigs(configDir?: string): any;
    
            // Return the sources for the configurations
            getConfigSources(): IConfigSource[];
            
            // Returns a new deep copy of the current config object, or any part of the config if provided.
            toObject(config?: any): any;
    
            /**
             * This allows module developers to attach their configurations onto
             * the 6 years agoInitial 0.4 checkin default configuration object so
             * they can be configured by the consumers of the module.
             */
            setModuleDefaults(moduleName:string, defaults:any): any;
        }
    
        interface IConfig {
            // Changed the get method definition.
            get<K extends keyof Config>(setting: K): Config[K];
            has(setting: string): boolean;
            util: IUtil;
        }
    
        interface IConfigSource {
            name: string;
            original?: string;
            parsed: any;
        }
      }
    
      export = c;
    
    }

那么我可以这样做:

备选方案 1

使用node-config-ts

备选方案 2

node-config-ts 只在您每次 npm i 时更新类型,但如果您想更明确地了解您正在读取的配置文件,则备选方案 2 很好,因为它们直接导入你的项目。这也意味着 nx 等工具知道在配置文件发生变化时重新编译您的项目。

src/Config.ts

import config from 'config';
import DefaultConfig from '../config/default';
import CustomEnvironmentVariables from '../config/custom-environment-variables.json';
// If you have more configuration files (eg. production.ts), you might want to add them here.

export const Config = config.util.toObject() as typeof DefaultConfig & typeof CustomEnvironmentVariables;

src/app.ts

import {Config} from './Config';

// Has the correct type of "string"
console.log(Config.server);

tsconfig.json

{
  // ...
  "compilerOptions": {
    // ...
    // add these if you want to import .json configs
    "esModuleInterop": true,
    "resolveJsonModule": true,
  },
}

如果您正在使用 monorepo 并尝试在子项目中导入 default.ts,您可能会收到错误...

error TS6059: File 'config/default.ts' is not under 'rootDir' 'my-project'. 'rootDir' is expected to contain all source files`. 

...那么您可能必须实施 this answer.