Benson Toh
Benson Toh

Reputation: 2128

No index signature with a parameter of type 'string' was found on type 'string | number | EnvType'

How do I get rid of this error at config[curr][targetEnv] ???

interface EnvType {
  dev: string;
  staging: string;
  production: string;
}

type Config = {
  [key: string]: number | string | EnvType;
};

const config: Config = {
  networkTimeout: 10000,
  apiHost: {
    dev: 'http://localhost:8080',
    staging: 'https://staging.example.com',
    production: 'https://example.com',
  },
};

const targetEnv = process.env.TARGET_ENV || 'dev';

const mappedConfig = Object.keys(config).reduce((acc, curr) => {
  const currValue = config[curr];

  // string or number or boolean; just return the value
  if (typeof currValue !== 'object') {
    return { ...acc, [curr]: currValue };
  }

  // is object; retrieve value by env
  if (typeof currValue === 'object') {
    return { ...acc, [curr]: config[curr][targetEnv] }; // error on this line
  }

  // do nothing
  return { ...acc };
}, {});

export default mappedConfig;

Upvotes: 0

Views: 125

Answers (2)

Nenad
Nenad

Reputation: 26727

First you have to constrain your process.env.TARGET_ENV, to ensure that value can be only dev, staging or production:

const targetEnv = (process.env.TARGET_ENV as keyof EnvType) ​|| 'dev';

Secondly, cast config[curr] as EnvType inside of typeof currValue === 'object' condition. That way you tell to TypeScript that you're sure that config[curr] returns correct EnvType, and not string or number when if condition is met.

// is object; retrieve value by env
if (typeof currValue === 'object') {
    return { ...acc, [curr]: (config[curr] as EnvType)[targetEnv] }; // error on this line
}

Full example would be:

interface EnvType {
    dev: string;
    staging: string;
    production: string;
  }
  
  type Config = {
    [key: string]: number | string | EnvType;
  };
  
  const config: Config = {
    networkTimeout: 10000,
    apiHost: {
      dev: 'http://localhost:8080',
      staging: 'https://staging.example.com',
      production: 'https://example.com',
    },
  };
  
  const targetEnv = process.env.TARGET_ENV as keyof EnvType || 'dev'; // added `as keyof`
  
  const mappedConfig = Object.keys(config).reduce((acc, curr) => {
    const currValue = config[curr];
  
    // string or number or boolean; just return the value
    if (typeof currValue !== 'object') {
      return { ...acc, [curr]: currValue };
    }
  
// is object; retrieve value by env
if (typeof currValue === 'object') {
    return { ...acc, [curr]: (config[curr] as EnvType)[targetEnv] }; // added `as`
}
  
    // do nothing
    return { ...acc };
  }, {});
  
  export default mappedConfig;

Upvotes: 1

liamgbs
liamgbs

Reputation: 5570

You're trying to look up a value using a string key. It will work for config[curr] because of this line in your config type type:

[key: string]: number | string | EnvType;

But then you're trying to do the same thing in your object of EnvType.

You need to do the same thing for that interface like so:

interface EnvType {
  [key: string]: string;
  dev: string;
  staging: string;
  production: string;
}

After that the problem will likely become that config can be a number or a string, both of which can't be indexed like that.

Upvotes: 0

Related Questions