TypeScript: Iterating over the interface fields does not work

Viewed 5299

I'm trying to iterate over the keys of an object that has an interface, but TypeScript does not recognise the type of the key.

interface Resources {
  food?: number
  water?: number
  wood?: number
  coal?: number
  stone?: number
  metal?: number
  oil?: number
  power?: number
}

class Game {
  resources: Resources = {}

  addResources = (newResources: Resources) => {
    Object.keys(newResources).forEach(key => {
      // Error:(17, 11) TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Resources'.
     //  No index signature with a parameter of type 'string' was found on type 'Resources'.
      if (this.resources[key]) {
        this.resources[key] += newResources[key]
      } else {
        this.resources[key] = newResources[key]
      }
    })
  }
}

How should I type it so Typescript will understand the iteration?

3 Answers

Yes, Object.keys() returns string[] and this is intentional https://github.com/Microsoft/TypeScript/issues/12870

(Object.keys(newResources) as Array<keyof Resources>).forEach(...) for the rescue.

UPD

(Object.keys(newResources) as Array<keyof typeof newResources>).forEach(...) also helps.

The interface does not exist in the browser, TypeScipt is only a compiler concept. Once your code is compiled to JavaScript and running in the browser there is no concept of the interface left. The interface exists only to strongly type the code during development, it is completely lost at run time.

If you want to get rid of the compiler error add a dynamic property.

interface Resources {
  food?: number
  water?: number
  wood?: number
  coal?: number
  stone?: number
  metal?: number
  oil?: number
  power?: number
  [key: string]?: any
}
Related