'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 1:[1]
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.
Solution 2:[2]
for..in
When looking at the Typescript documentation (Typescript: Iterators and Generators), we see that the for..in syntax will iterate over the keys of the object.
for..in returns a list of keys on the object being iterated, whereas for..of returns a list of values of the numeric properties of the object being iterated.
We can use that to our advantage to index into our object and get the strongly typed value:
// Go through each key of the indexed object:
for (const key in indexedObject)
{
// Get the indexed item by the key:
const indexedItem = indexedObject[key];
// Now we have the item.
// Use it...
}
Solution
We can use that to get an elegant solution to the question:
// Go through each key in the bigObject:
for (const key in bigObject)
{
// Get the strongly typed value with this name:
const value = bigObject[key];
// Now we have the the strongly typed value for this key (depending on how bigObject was typed in the first place).
// Do something interesting with the property of bigObject...
}
Solution 3:[3]
After playing with it a while I found a solution that makes the TS compiler happy. Declare the key outside the for loop:
type TObj = {
key1: string;
key2: string
}
const obj: TObj = {
key1: "foo",
key2: "bar"
};
// Declare the key outside the for loop
let t: keyof TObj;
for(t in errors) {
errors[t]; // no compiler error
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Paleo |
Solution 2 | Luke Machowski |
Solution 3 | Hayden Linder |