Iterating over Typescript Map

TypescriptIteratorMaps

Typescript Problem Overview


I'm trying to iterate over a typescript map but I keep getting errors and I could not find any solution yet for such a trivial problem.

My code is:

myMap : Map<string, boolean>;
for(let key of myMap.keys()) {
   console.log(key);
}

And I get the Error:

>Type 'IterableIteratorShim<[string, boolean]>' is not an array type or a string type.

Full Stack Trace:

 Error: Typescript found the following errors:
  /home/project/tmp/broccoli_type_script_compiler-input_base_path-q4GtzHgb.tmp/0/src/app/project/project-data.service.ts (21, 20): Type 'IterableIteratorShim<[string, boolean]>' is not an array type or a string type.
    at BroccoliTypeScriptCompiler._doIncrementalBuild (/home/project/node_modules/angular-cli/lib/broccoli/broccoli-typescript.js:115:19)
    at BroccoliTypeScriptCompiler.build (/home/project/node_modules/angular-cli/lib/broccoli/broccoli-typescript.js:43:10)
    at /home/project/node_modules/broccoli-caching-writer/index.js:152:21
    at lib$rsvp$$internal$$tryCatch (/home/project/node_modules/rsvp/dist/rsvp.js:1036:16)
    at lib$rsvp$$internal$$invokeCallback (/home/project/node_modules/rsvp/dist/rsvp.js:1048:17)
    at lib$rsvp$$internal$$publish (/home/project/node_modules/rsvp/dist/rsvp.js:1019:11)
    at lib$rsvp$asap$$flush (/home/project/node_modules/rsvp/dist/rsvp.js:1198:9)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickCallback (internal/process/next_tick.js:98:9)

I'm using angular-cli beta5 and typescript 1.8.10 and my target is es5. Has anyone had this Problem?

Typescript Solutions


Solution 1 - Typescript

You could use Map.prototype.forEach((value, key, map) => void, thisArg?) : void instead

Use it like this:

myMap.forEach((value: boolean, key: string) => {
    console.log(key, value);
});

Solution 2 - Typescript

es6

for (let [key, value] of map) {
    console.log(key, value);
}

es5

for (let entry of Array.from(map.entries())) {
    let key = entry[0];
    let value = entry[1];
}

Solution 3 - Typescript

Just use Array.from() method to convert it to an Array:

myMap : Map<string, boolean>;
for(let key of Array.from( myMap.keys()) ) {
   console.log(key);
}

Solution 4 - Typescript

Using Array.from, Array.prototype.forEach(), and arrow functions:

Iterate over the keys:

Array.from(myMap.keys()).forEach(key => console.log(key));

Iterate over the values:

Array.from(myMap.values()).forEach(value => console.log(value));

Iterate over the entries:

Array.from(myMap.entries()).forEach(entry => console.log('Key: ' + entry[0] + ' Value: ' + entry[1]));

Solution 5 - Typescript

This worked for me. TypeScript Version: 2.8.3

for (const [key, value] of Object.entries(myMap)) { 
    console.log(key, value);
}

Solution 6 - Typescript

Per the TypeScript 2.3 release notes on "New --downlevelIteration": > for..of statements, Array Destructuring, and Spread elements in Array, Call, and New expressions support Symbol.iterator in ES5/E3 if available when using --downlevelIteration

This is not enabled by default! Add "downlevelIteration": true to your tsconfig.json, or pass --downlevelIteration flag to tsc, to get full iterator support.

With this in place, you can write for (let keyval of myMap) {...} and keyval's type will be automatically inferred.


Why is this turned off by default? According to TypeScript contributor @aluanhaddad, > It is optional because it has a very significant impact on the size of generated code, and potentially on performance, for all uses of iterables (including arrays).

If you can target ES2015 ("target": "es2015" in tsconfig.json or tsc --target ES2015) or later, enabling downlevelIteration is a no-brainer, but if you're targeting ES5/ES3, you might benchmark to ensure iterator support doesn't impact performance (if it does, you might be better off with Array.from conversion or forEach or some other workaround).

Solution 7 - Typescript

This worked for me.

Object.keys(myMap).map( key => {
    console.log("key: " + key);
    console.log("value: " + myMap[key]);
});

Solution 8 - Typescript

I'm using latest TS and node (v2.6 and v8.9 respectively) and I can do:

let myMap = new Map<string, boolean>();
myMap.set("a", true);
for (let [k, v] of myMap) {
    console.log(k + "=" + v);
}

Solution 9 - Typescript

You can also apply the array map method to the Map.entries() iterable:

[...myMap.entries()].map(
     ([key, value]: [string, number]) => console.log(key, value)
);

Also, as noted in other answers, you may have to enable down level iteration in your tsconfig.json (under compiler options):

  "downlevelIteration": true,

Solution 10 - Typescript

On Typescript 3.5 and Angular 8 LTS, it was required to cast the type as follows:

for (let [k, v] of Object.entries(someMap)) {
    console.log(k, v)
}

Solution 11 - Typescript

Just a simple explanation to use it in an HTML document.

If you have a Map of types (key, array) then you initialise the array this way:

public cityShop: Map<string, Shop[]> = new Map();

And to iterate over it, you create an array from key values.

Just use it as an array as in:

keys = Array.from(this.cityShop.keys());

Then, in HTML, you can use:

*ngFor="let key of keys"

Inside this loop, you just get the array value with:

this.cityShop.get(key)

Done!

Solution 12 - Typescript

I tried using Array.from( myMap.keys() ) to get an array of keys in my VSCode extension that's implemented using node.js, but it did not work, even after adding "downlevelIteration": true to my tsconfig.json with the target set to es2017 as suggested by Ahmed Fasih and others.

What ultimately worked was Jason Slobotski's suggestion to use Object.keys:

let keys = Object.keys(myMap);

Solution 13 - Typescript

If you don't really like nested functions, you can also iterate over the keys:

myMap : Map<string, boolean>;
for(let key of myMap) {
   if (myMap.hasOwnProperty(key)) {
       console.log(JSON.stringify({key: key, value: myMap[key]}));
   }
}

Note, you have to filter out the non-key iterations with the hasOwnProperty, if you don't do this, you get a warning or an error.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmweView Question on Stackoverflow
Solution 1 - TypescriptrinukkusuView Answer on Stackoverflow
Solution 2 - TypescriptOded BreinerView Answer on Stackoverflow
Solution 3 - Typescript6qatView Answer on Stackoverflow
Solution 4 - TypescriptTobiasView Answer on Stackoverflow
Solution 5 - TypescriptDebashish SenView Answer on Stackoverflow
Solution 6 - TypescriptAhmed FasihView Answer on Stackoverflow
Solution 7 - TypescriptJason SlobotskiView Answer on Stackoverflow
Solution 8 - TypescriptlazieburdView Answer on Stackoverflow
Solution 9 - TypescriptchamView Answer on Stackoverflow
Solution 10 - TypescriptConstantin KonstantinidisView Answer on Stackoverflow
Solution 11 - TypescriptSophie C MusicalView Answer on Stackoverflow
Solution 12 - TypescriptArt WalkerView Answer on Stackoverflow
Solution 13 - TypescriptpeterhView Answer on Stackoverflow