typescriptecmascript-6

How to iterate over keys of a generic object in TypeScript?


I need to iterate over a large object which is just typed as "object". It contains an unknown number of objects of the same type.

In older posts I had found solutions using a generator within a custom Symbol.iterator function to make the large object iterable with a for..of loop.

But it seems to me, now in 2017, just using Object.keys is actually easier:

Object.keys(bigObject).forEach((key:string)=>{
console.log(bigObject[key]);
});

This actually runs just fine! But the TypeScript compiler keeps giving me the error "error TS7017: Element implicitly h as an 'any' type because type '{}' has no index signature"

Does anybody have an idea what I am missing here? Or what is the current best practice to do such an iteration with ES2015 and TypeScript (2.2.2)?


Solution

  • A dictionary type

    It contains an unknown number of objects of the same type.

    Maybe with a generic interface BigObject<T> for your dictionary?

    interface BigObject<T> {
        [index: string]: T
    }
    
    let bigObject: BigObject<object> = {}
    Object.keys(bigObject).forEach(key => {
      console.log(bigObject[key])
    })
    

    Here I wrote the type object in let bigObject: BigObject<object>. You can use a better type.

    Notice about the for .. in solution

    I've noticed that other answers suggest a for .. in loop. This was the only way to iterate through the properties of an object in the 20s, and somehow it makes me nostalgic. It's nice to use these old tricks. However, there's a little pitfall to avoid. It is mandatory to use Object.hasOwn() (the replacement of hasOwnProperty). Here is the correct way to use a for .. in loop:

    for (const propName in obj) {
      if (!Object.hasOwn(obj, propName)) continue;
      // ...
    }
    

    See also: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in#iterating_own_properties

    To illustrate the problem, let's imagine that somewhere in a library you are importing is this kind of code :

    Object.prototype.extraProperty = "This is inherited";
    

    … then all your for .. in loops will iterate on the inherited extraProperty too.

    One last thing to know: as far as performance is concerned, iteration on Object.keys is faster than a for .. in loop.