338

In my code, I have a couple of dictionaries (as suggested here) which is String indexed. Due to this being a bit of an improvised type, I was wondering if there any suggestions on how I would be able to loop through each key (or value, all I need the keys for anyway). Any help appreciated!

myDictionary: { [index: string]: any; } = {};
Yves M.
  • 29,855
  • 23
  • 108
  • 144
ben657
  • 3,723
  • 3
  • 16
  • 14
  • 1
    Did you try: `for (var key in myDictionary) { }`? Inside the loop, you'd use `key` to get the key, and `myDictionary[key]` to get the value – Ian Apr 23 '13 at 16:15
  • @Ian Just tried that, doesn't seem to be working. No errors, but nothing runs within the statement – ben657 Apr 23 '13 at 16:21
  • 1
    @Ian Ah sorry, some code elsewhere was messing with it. That works perfectly! Care to make it an answer so I can choose it? – ben657 Apr 23 '13 at 16:38

11 Answers11

442

To loop over the key/values, use a for in loop:

for (let key in myDictionary) {
    let value = myDictionary[key];
    // Use `key` and `value`
}
kcpr
  • 1,055
  • 1
  • 12
  • 28
Ian
  • 50,146
  • 13
  • 101
  • 111
  • Must use the "key" as variable name? – Yiping Sep 05 '15 at 06:13
  • 9
    This isn't safe in general; it needs the hasOwnProperty test (as in Jamie Stark's answer) or something else. – Don Hatch Feb 03 '16 at 19:30
  • 39
    @DonHatch It's actually very safe in general. It's not safe in very specific cases (like when you include libraries which modify prototypes incorrectly, or purposely modify prototypes incorrectly). It's up to the developer whether to bloat their code with most-likely-unnecessary checks – Ian Feb 03 '16 at 19:38
  • 1
    @Ian - My thinking is that I wouldn't use it without additional safeguards since it seems like an accident waiting to happen, e.g. if the code finds its way into a utility function, and then someone passes that function a dictionary that's not simply an Object, but rather something with additional properties. Yes, as you say, it's up to the developer to weigh the likelihood and severity of such a scenario. For myself, the least mentally burdensome approach is to behave as though such a scenario is guaranteed to happen in all cases-- less to think about. – Don Hatch Feb 04 '16 at 03:43
  • 6
    @Ian The problem is that there are too many libraries which do modify object prototypes. It seems a bad idea to advocate this type of pattern when much better simple alternatives exist, such as `Object.keys(target).forEach(key => { let value = target(key); /* Use key, value here */ });`. If you must show this method, at least mention the risks and better alternatives for those who don't yet know better. – Yona Appletree Apr 13 '16 at 00:08
  • 11
    We already have es6 and TypeScript. Why does the problem of writing hasOwnProperty all the time remain unresolved? Even in 2017 and with all attention to JS. I am so disappointed. – Gherman Sep 25 '17 at 13:10
  • 4
    With map: `Object.entries(obj).map(([key, val]) => console.log(key, '=>', val));` – hkarask Nov 03 '19 at 10:27
  • Also consider to use a Map for the dictionary to avoid the problem with checking hasOwnProperty : `let myDictionary = new Map([ ["key1", "val1"], ["key2", "val2"], ]); myDictionary.forEach((key, value) => { console.log(key, value); });` – Philip Apr 17 '20 at 08:22
  • related: https://stackoverflow.com/a/45959874/997940 – Yoav Feuerstein Dec 16 '20 at 14:27
322

< ES 2017:

Object.keys(obj).forEach(key => {
  let value = obj[key];
});

>= ES 2017:

Object.entries(obj).forEach(
  ([key, value]) => console.log(key, value)
);
Guillaume Vincent
  • 13,355
  • 13
  • 76
  • 103
Stephen Paul
  • 37,253
  • 15
  • 92
  • 74
  • This is the solution I was looking for as it will allow me to sort the keys before iteration – Andrew Oct 18 '16 at 15:57
  • 2
    See [here](http://stackoverflow.com/a/39815452/968003) how to make `Object.entries` to work in TypeScript – Alex Klaus Mar 21 '17 at 23:29
119

How about this?

for (let [key, value] of Object.entries(obj)) {
    ...
}
Resigned June 2023
  • 4,638
  • 3
  • 38
  • 49
  • 1
    It requires lib es2017 in tsconfig. See https://stackoverflow.com/questions/45422573/property-entries-does-not-exist-on-type-objectconstructor – Stéphane Mar 12 '19 at 17:15
  • This is what I needed to get past the Typescript error on obj[key] "No index signature..." because I explicitly set my obj type as { [key: string]: string } and not wanted to use { [key: string]: any }. With this I can just access 'value'. Thanks – ggedde Nov 06 '19 at 10:31
  • And if you want to ignore `key` at all, simply leave it blank: `[ , value]`. (Thanks to [this issue comment](https://github.com/eslint/eslint/issues/4880#issuecomment-265014334).) – Dominik Apr 30 '20 at 20:28
  • 1
    this is the only valid way I've found so far to iterate through non string key index types – nemo Oct 11 '20 at 11:30
  • 2
    This should be at the top. It's clean, it looks like a loop should look and it does not iterate over the prototype chain. – Ruslan Plastun Aug 20 '21 at 10:49
  • How do you define the key and value in typescript here? – wongz Dec 15 '21 at 03:55
  • @wongz `let [key, value]` *is* the definition of `key` and `value`. – Resigned June 2023 Dec 15 '21 at 04:15
  • 1
    @RadonRosborough It seems that oftentimes, even if defining the object, when looping through the object with this pattern, it loses the type safety for key and value. Or at least the interconnectedness of key and value type safety. Just curious what the pattern is to define the types for key and value if we want to be more explicit. Or is that not an option because as you said... it is self defining – wongz Dec 15 '21 at 04:24
  • @wongz Ah, yes. To my knowledge it's not possible to set a type constraint on a destructured parameter like this. However, I might just not have good enough knowledge of the syntax, as I haven't written serious TypeScript in the last few years. – Resigned June 2023 Dec 19 '21 at 17:08
55

There is one caveat to the key/value loop that Ian mentioned. If it is possible that the Objects may have attributes attached to their Prototype, and when you use the in operator, these attributes will be included. So you will want to make sure that the key is an attribute of your instance, and not of the prototype. Older IEs are known for having indexof(v) show up as a key.

for (const key in myDictionary) {
    if (myDictionary.hasOwnProperty(key)) {
        let value = myDictionary[key];
    }
}
Francesco Borzi
  • 56,083
  • 47
  • 179
  • 252
Jamie Starke
  • 8,776
  • 3
  • 38
  • 58
  • 4
    Not trying to split hairs, but since we're talking type script, shouldn't you use let key instead of var key? Nice answer thank you. – Luke Dupin Mar 11 '16 at 01:03
  • 3
    In fact, with the current version of type script the `key` and `value` can be `const`. – Patrick Desjardins Mar 03 '17 at 05:19
  • 2
    It's better to not call the `hasOwnProperty` check from the target object, instead do this: `...if (Object.prototype.hasOwnProperty.call(myDictionary, key))...` Else, if you are using eslint with `no-prototype-builtins` rule, it will emit an error. – sceee Apr 30 '20 at 06:38
30

Shortest way to get all dictionary/object values:

Object.keys(dict).map(k => dict[k]);

Or this ways:

Object.entries(dict).map([k,v] => /* ... */);
k06a
  • 17,755
  • 10
  • 70
  • 110
3

If you just for in a object without if statement hasOwnProperty then you will get error from linter like:

for (const key in myobj) {
   console.log(key);
}
WARNING in component.ts
for (... in ...) statements must be filtered with an if statement

So the solutions is use Object.keys and of instead.

for (const key of Object.keys(myobj)) {
   console.log(key);
}

Hope this helper some one using a linter.

Binh Ho
  • 3,690
  • 1
  • 31
  • 31
1

Ians Answer is good, but you should use const instead of let for the key because it never gets updated.

for (const key in myDictionary) {
    let value = myDictionary[key];
    // Use `key` and `value`
}
finnk
  • 123
  • 1
  • 1
  • 12
1

With es2019, this is now even simpler:

  1. We can use of systematic
  2. No longer need to wrap the dictionary with Object.entries

Example:

let someMap: Map<number, number> = new Map()
someMap.set(3, 7);
someMap.set(4, 12);
for (let [key, value] of someMap) {
    console.log(key, value)
}

Output:

3 7
4 12
Yuchen
  • 30,852
  • 26
  • 164
  • 234
1

If you want to loop only through object value take a look at Object.values

marko424
  • 3,839
  • 5
  • 17
  • 27
0

To get the keys:

function GetDictionaryKeysAsArray(dict: {[key: string]: string;}): string[] {
  let result: string[] = [];
  Object.keys(dict).map((key) =>
    result.push(key),
  );
  return result;
}
Ribeiro
  • 364
  • 1
  • 3
  • 12
0

this is my function, i hope this help

function recordToArray<TypeOfSchema>(
  data: Record<string, TypeOfSchema>
): Array<TypeOfSchema> {
  return Object.keys(data).map((key: string) => ({ id: key, ...data[key] }));
}
loc.dang
  • 374
  • 3
  • 19