Daryl
Daryl

Reputation: 18895

How to Iterate Over String Indexed Array In TypeScript?

I have defined a static property as such:

private static colorsByName: { [index: string]: MyColorClass}

but when I attempt to use for... of from the answer listed here: TypeScript for-in statement

for(let value of MyClass.colorsByName) {
    ...
}

I get an error:

Type { [index: string]: MyColorClass; } is not an array type or a string type.

If I switch over to using for in, the error goes away, but value is typed as any.

for(let value of MyClass.colorsByName) {
    ...
}

What is the actual type of value in this case? Ideally I'd like to loop through all values in the colorsByName property, either in a pair approach, or just to get MyColorClass types returned.

for(let value of MyClass.colorsByName) {
    // value: MyColorClass
}

What are my options?

Upvotes: 14

Views: 20706

Answers (2)

David Sherret
David Sherret

Reputation: 106790

It's not an array—it's an object with string keys and values of type MyColorClass.

What you can do, is turn it into an array by getting an array of the object's keys then mapping the keys to the properties of the object:

const colors = Object.keys(MyClass.colorsByName).map(key => MyClass.colorsByName[key]);

Since you might do this a lot, you could create a reusable function to turn the properties into an array:

function propsToArray<T>(obj: { [index: string]: T; } | { [index: number]: T; }) {
    return Object.keys(obj).map(prop => obj[prop]);
}

Then you use it like so:

for (const color of propsToArray(MyClass.colorsByName)) {
    // use color here
}

Side note: You may just want to store this cached on a static property of MyClass.

Object.values

Alternatively, you could also use Object.values():

for (const color of Object.values(MyClass.colorsByName)) {
    // use color here
}

But you might need to add a polyfill if you use that.

Upvotes: 18

Luke Machowski
Luke Machowski

Reputation: 4211

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 named color:
for (const colorName in colorsByName)
{
   // Get the strongly typed color with this name:
   const color = colorsByName[colorName]; // : MyColorClass
   // Now we have the the strongly typed color with this name.

   // Paint the world in a techni-colour rainbow...
}

Upvotes: 7

Related Questions