1

I have a node project with typescript and I'm trying to read the right url from a json object. However when using square bracket notation I get undefined.

{
    "env":"dev",
    "dev":{
        "url": "url1"
    },
    "aws":{
        "url": "url2"
    }
}

For some reason this does not work:

const url = config[config.env].url;

The code below accomplishes what I need, but it is not as flexible as the above and I want to understand why it does not work the other way.

const cenv:string = config.env;
    let url=null;
    if( cenv === "dev")
        url = config["dev"].url;
    else
        url = config["aws"].url;

This is my tsconfig file:

{
  "compilerOptions": {
    "lib": [
      "es2017"
    ],
    "moduleResolution": "node",
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "sourceMap": true,
    "target": "es2017",
    "outDir": "lib",
    "resolveJsonModule": true
  },
  "exclude": [
    "node_modules"
  ]
}

The json is imported to the project like so:

import * as config from './config.json';

2 Answers 2

1

The reason this doesn't work is because Typescript infers the value for env to be of type string, which means it can be any string value. You can see this when you inspect typeof config:

enter image description here

Because Typescript thinks that env can be any string value, it throws an error. What would happen for example if you compiled this code, but then changed the env value to be "foobar"? The code would throw, and Typescript guards you from this.

Sign up to request clarification or add additional context in comments.

Comments

1

I'd suggest creating config folder

config/
  settings.dev.json
  settings.prod.json
  index.js

// index.js
module.exports = function(){
    switch(process.env.NODE_ENV){
        case 'development':
            return require('./settings.dev.json');

        case 'production':
            return require('./settings.prod.json');

        default:
            return {error or other settings};
    }
};

If you want to use approach you can do it this way:

enum Enivornment {
  Dev = "dev",
  Aws = "aws"
}

type Config = {
  "env": Enivornment,
} & {
  [key in Enivornment]: ConfigItem
}

// this will help you have all environments in sync
type ConfigItem = {
  "url": string
} 

const config: Config = {
    "env": Enivornment.Dev,
    [Enivornment.Dev]: {
        "url": "url1"
    },
    [Enivornment.Aws]:{
        "url": "url2"
    }
}

You can test it here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.