0

I'm trying to loop over the keys of an object and attach the value as id / for now console.log() it. I receive the following error:

  • Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'StartItems'. No index signature with a parameter of type 'string' was found on type 'StartItems'

Now I thought I have my Interface set up correctly, but somehow Typescript doesnt understand that the placeholder "key" in my loop contains the valid "key" defined in the interface. Here's the code:

/* Some Notes:
 * heroStartItems[GameSettings.heroId] returns the correct object
 * heroStartItems[GameSettings.heroId][key] compiles successfully although
   the TS error message.
 */
// the loop in which the error occurs.
for (const key in heroStartItems[GameSettings.heroId]) {
      const div = document.createElement('div');
      //const img = document.createElement('img');
      div.classList.add(key);
      console.log(heroStartItems[GameSettings.heroId][key]);

      //div.id = heroStartItems[key].toString();
      // div.appendChild(img);
      heroItems.appendChild(div);
    }

// heroStartItems looks like this:
export const heroStartItems: heroItemSlots = {
  [Heroes['Anti-Mage']]: {
    item1: ItemsEnum['Tango'],
    item2: ItemsEnum['Healing Salve'],
    item3: ItemsEnum['Quelling Blade'],
    item4: ItemsEnum['Iron Branch'],
    item5: ItemsEnum['Iron Branch'],
    item6: ItemsEnum['Slippers of Agility'],
  },
  .
  .
  .
}

// heroItemSlots looks like this:
export interface heroItemSlots {
  [key: string]: StartItems;
}

interface StartItems {
  item1: number | null;
  item2: number | null;
  item3: number | null;
  item4: number | null;
  item5: number | null;
  item6: number | null;
}

After compiling, I receive the correct output, which are the numbers of ItemsEnum.

I have tried to implement a typeguard inside the for loop like so:

if (key instanceof StartItems) {
 console.log(heroStartItems[GameSettings.heroId][key]);
}

But the error persists. I'm pretty lost here and sure that I do miss some key concepts of Typescript. I appreciate any help. Thanks in advance!

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Mohemi
  • 161
  • 2
  • 8
  • 1
    Welcome to Stack Overflow! When posting, please be sure to reduce the code to the minimum necessary to replicate the problem (more: [mcve]). In this case, that would look something like [this](https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgMpjlMBJSBbAZ2QG8AoZZYfARgC5kQBXPAI2mQB8HGAbHgbnKV8AJnpNW7Lkz6CKVCHgDM45myidusoQrwAWVZI3TeAnfgCsh9Zpln5+AGzWpWswF9SpACYQEPTBQeCDBhRQJ6dEwcfAJBUhgAew0ACgREkAJQgGsIAE9KEDDCAEoSIQp0zMTggDoeRIBzFN0CAG1cvIBdEsFPIA). – T.J. Crowder Aug 16 '21 at 08:55
  • 1
    The type of `key` in your `for-in` loop is `string`, not `keyof StartItems`. `StartItems` has no index signature, so you can't index into it with a string. You can get around it by making sure `key` is `keyof StartItems` in one of two ways: Either declare it before the loop (`let key: keyof StartItems;` then `for (key in /*...*/)` or use a type assertion on it (`console.log(heroStartItems[GameSettings.heroId][key as keyof StartItems]);`). – T.J. Crowder Aug 16 '21 at 09:00
  • 1
    @T.J.Crowder Thank you, I will read up on the problem styling. And the suggestions did the trick :) – Mohemi Aug 16 '21 at 09:04
  • Glad that helped! Just for what it's worth: [playground](https://tsplay.dev/mMRzkW). I don't know why the key in a `for-in` loop is `string` rather than `keyof` the type of what you're looping through (maybe it has to do with inherited properties), or why you can't use a type annotation on the `for-in` key, but I suspect there are good reasons in the general case. But when you know it's valid, even though it's a type assertion (blech), it seems reasonable. – T.J. Crowder Aug 16 '21 at 09:05

0 Answers0