6

I have this really easy problem, where I want to loop through an Object in TypeScript.

const an_object = {
    one: 1,
    two: 2,
    three: 3
};

for (let key in an_object) {
    let value = an_object[key];
    // Do something with value
}

This row let value = an_object[key]; is causing a TypeScript error:

[react-scripts] Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ one: number; two: number; three: number; }'.

I'm new to TypeScript and don't really understand the problem.

This works fine on JavaScript but not on TypeScript.

Any suggestions on how to loop through an object in TypeScript correctly, without getting errors?

OuuGiii
  • 1,053
  • 1
  • 11
  • 31
  • [Duplicate?](https://stackoverflow.com/questions/57086672/element-implicitly-has-an-any-type-because-expression-of-type-string-cant-b) – Svit Jan 13 '20 at 20:07
  • the `value` will be overwritten each time, why do you need that so? –  Jan 13 '20 at 22:09
  • @Lonely I'm sorry for not making it clear enough, I updated the code so you can see that you do something with the value. – OuuGiii Jan 14 '20 at 00:40
  • @AleksaSvitlica I wouldn't call it a duplicate as this question is shorter and clearer. The answer to that question also answers a specific problem, and not a more general one, which I have shown here. – OuuGiii Jan 14 '20 at 01:06
  • Weirdly enough, I didn't get the correct answer from StackOverflow, but from my friends. And nobody answered my question, that's why I decided to answer the question myself. Please correct me if I'm wrong. – OuuGiii Feb 19 '20 at 08:16

3 Answers3

4

For this purpose, I usually write a helper function, so that my "for each object property" loops can be written like follows:

objForEach(an_object, (k, v) => {
    console.log('key', k, 'value', v);
});

The implementation is below. Helpfully, by making it generic, the parameters k and v can have their types inferred correctly depending on an_object:

function objForEach<T>(obj: T, f: (k: keyof T, v: T[keyof T]) => void): void {
    for (let k in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, k)) {
            f(k, obj[k]);
        }
    }
}

Note that I've used hasOwnProperty to check that the property belongs to the object itself rather than another object in its prototype chain (see e.g. this question).

kaya3
  • 47,440
  • 4
  • 68
  • 97
4

TypeScript is named TYPEScript for a reason.

The problem is that it's not specified what will be inside the object.

Any suggestions on how to loop through an object in TypeScript correctly, without getting errors?

To do this correctly you should specify what is inside the object. This can be done by:

  1. creating an interface
interface MyObjectsInterface {
    [key: string]: number;
}
  1. assign it to the object.
const an_object: MyObjectsInterface = {
    one: 1,
    two: 2,
    three: 3
};
  1. now you can use the value in the forloop
for (let key in an_object) {
    let value: number = an_object[key];
    // Do something with value
}

In this way, you will always know what will be inside an object.

OuuGiii
  • 1,053
  • 1
  • 11
  • 31
3

As @OuuGiii puts it, it's TYPEscript. So just define the key for the loop variable. However, if you are lazy like me and don't wanna define an entire interface notice that you can do something like this:

{ // To make "key" a local variable it must be in a "block" (braces).
// If a block is not used, you cannot use another loop with this iteration
// variable This is especially important if, much like me, you have a bad habit
// of defining "i"s for all the loops.

    let key: keyof typeof an_object;
    for (key in an_object) {
        let value /*: typeof an_object[typeof key] */ = an_object[key];
        // Do something with value
    }
}
Davoodeh
  • 69
  • 1
  • 5