如何在打字稿中使用节点配置?
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
备选方案 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.
安装 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
备选方案 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.