How to use node-config in typescript with custom config interface?

2.2k views Asked by At

This is a follow up to How to use node-config in typescript? since I couldn't find a proper answer.

I'm relatively new to TS and I'm trying to convert our configs from json to typescript, while trying to incorporate types on the config.

What we currently have is something like:

// default.json
{
  "server": {
    "timeout": 10
  }
}

// some-code.ts
import config from 'config';
...
const serverTimeout = config.get<number>('server.timeout'); // 10

Here, we are able to get required configs, but we need to specify the type via generics in code. I'm trying to incorporate (relatively) stronger typing.

Dry conversion:

// default.ts
import { MyConfig } from './config-schema.ts'

const conf: MyConfig = {
  "server": {
    "timeout": 10
  }
};

export default conf;

// config-schema.ts
export interface MyConfig {
  server: {
    timeout: number;
  }
}

// some-code.ts
import config from 'config';

console.log(config); // { "server": { "timeout": 10 } }
console.log(config.get<number>('server.timeout')); // 10
console.log((config as any).server.timeout); // 10
console.log(config.server.timeout); // obviously a compile time error.

As you can see, the last form will NOT work and results in compile time ERROR. I somehow want config to conform to the shape of MyConfig so that config.server.timeout is possible with strong type number.

I need to somehow extend the IConfig interface with MyConfig or force a re-typing of config to IConfig & MyConfig.

My attempt:

// config-schema.ts
import config from 'config';

interface MyConfig {
  server: {
    timeout: number;
  }
}

export (config as any as MyConfig);

// some-code.ts
import config from './config-schema';

console.log(config.server.timeout); // 10

This works, but somehow doesn't feel right to me.

Problems

  • Forced to use any... can this be avoided somehow ?
  • Need to do something like import config from '../../core/config-schema'; -> looks ugly, path different for different files, need all project collaborators to follow convention... is it possible to keep it as import config from 'config'; and have the magic abstracted out ?
  • Compile default.ts to default.js with tscat compile time (so that typescript is not a runtime dependency). Have updated env var NODE_CONFIG_DIR accordingly. Currently I do this, but the config object gets created with an extra hierarchy level. i.e. instead of config.server.timeout, it became config.default.server.timeout

Edit: Third question resolved -- see comment

0

There are 0 answers