遍历Typescript映射


134

我试图遍历一个打字稿图,但是我不断收到错误,并且对于这种琐碎的问题我找不到任何解决方案。

我的代码是:

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

我得到了错误:

类型'IterableIteratorShim <[string,boolean]>'不是数组类型或字符串类型。

全栈跟踪:

 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)

我正在使用angular-cli beta5和打字稿1.8.10,我的目标是es5。有人遇到过这个问题吗?


Answers:


210

您可以Map.prototype.forEach((value, key, map) => void, thisArg?) : void改用

像这样使用它:

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

15
刚遇到这个。至少根据指定for-of循环的MDN看来,TypeScript似乎没有遵守地图迭代的规范。.forEach是次优的,因为您无法打破它,AFAIK
Samjones

14
不知道为什么它的价值才是关键。似乎倒退。
Paul Rooney

@PaulRooney可能就是这样Array.prototype.map
艾哈迈德·法西

1
如果发现需要的内容,如何停止该迭代过程?
JavaRunner

36

只需使用Array.from()方法将其转换为Array

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

5
转换地图是一项非常耗性能的操作,而不是解决问题的正确方法,该问题实际上只是编译器隐藏了语言的核心部分。只需<any>投射地图即可进行迭代。
希尔夫斯'18

1
当心:我认为上述@Kilves建议将地图转换为“ any”是一种不错的解决方法。当我这样做时,代码可以毫无抱怨地进行编译和运行,但是Map实际上并没有被迭代-循环的内容从未执行过。Array.from()这里提出的策略确实对我有用。
mactyr

我也尝试过,它对我也不起作用,考虑到它 ES6的一部分,并且应该在大多数浏览器上“正常工作” ,这甚至更愚蠢。但是我想我们的有角霸王在zone.js中使用了一些神奇的巨型巨像,使其无法正常工作,因为他们讨厌ES6。叹。
希尔夫斯'18

35

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];
}

1
上面给出的es6版本未在严格模式下编译。
史蒂芬

谢谢你,先生。
Kitanga Nday

28

使用Array.fromArray.prototype.forEach()箭头函数

遍历

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

遍历

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

遍历条目

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

2
不知道为什么,我有Map <String,CustomeClass>之类的地图。除Array.from(myMap.values())。forEach(value => console.log(value));以外,以上方法均无效。
Rajashree Gr '18 -4-4

27

这对我有用。TypeScript版本:2.8.3

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

7
我通过将Object.entries(myMap)更改为myMap.entries()使它起作用。我喜欢这个答案,因为它避免了.forEach调用的错误处理陷阱。
占领

2
值得注意的是,如果您target输入的tsconfig内容es5会引发错误,但es6可以正常使用。您也可以for (const [key, value] of myMap)在定位时进行操作es6
本杰明·沃格勒

16

根据TypeScript 2.3发行说明中的​​“新建--downlevelIteration

for..of statements,“数组”,“调用”和“新”表达式中的,“数组解构”和“传播”元素在使用时支持ES5 / E3中的Symbol.iterator --downlevelIteration

默认情况下未启用此功能!添加"downlevelIteration": true到您的tsconfig.json,或将--downlevelIteration标记传递到tsc,以获得完整的迭代器支持。

使用此功能后,您可以进行写操作,for (let keyval of myMap) {...}并且keyval的类型将被自动推断。


为什么默认情况下将其关闭?根据TypeScript贡献者@aluanhaddad的说法

它是可选的,因为对于可迭代对象(包括数组)的所有使用,它对生成的代码的大小以及性能都有非常重要的影响。

如果可以将ES2015(定位"target": "es2015"tsconfig.jsontsc --target ES2015或更高版本)作为目标,那么启用就很downlevelIteration容易了,但是如果要定位ES5 / ES3,则可以进行基准测试以确保迭代器支持不会影响性能(如果这样做会更好)关与Array.from转换或forEach或其他一些解决方法)。


使用Angular启用此功能可以吗?
Simon_Weaver


8

我正在使用最新的TS和节点(分别为v2.6和v8.9),并且可以执行以下操作:

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

你能确认你首先要设置"downlevelIteration": true你的tsconfig.json
艾哈迈德·法西

3
我没有downlevelIteraton设定,es2017但是我的目标是。
lazieburd

我不能为Map <string,CustomClass []>元素执行此操作吗?编译器说它不是类型或字符串类型的数组。
Rajashree Gr '18

在2.8上这对我不起作用-我得到了Type 'Map<K, V>' is not an array type or a string type.
Simon_Weaver

3

您还可以将数组映射方法应用于可迭代的Map.entries():

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

另外,如其他答案所述,您可能必须在tsconfig.json中启用下层迭代(在编译器选项下):

  "downlevelIteration": true,

TypeScript 2.3中引入了此功能。TypeScript 1.8.10
mwe

如果您不能使用“ downlevelIteration”,则可以使用:const projected = Array.from(myMap).map(...);
Efrain

1

只是在HTML文档中使用它的简单说明。

如果您具有Map类型(键,数组),则可以通过以下方式初始化数组:

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

为了对其进行迭代,您需要根据键值创建一个数组。

只需将其用作数组即可,如:

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

然后,在HTML中,您可以使用:

*ngFor="let key of keys"

在此循环内,您只需使用以下命令即可获得数组值:

this.cityShop.get(key)

做完了!



-1

如果您真的不喜欢嵌套函数,则还可以遍历键:

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

请注意,您必须使用过滤掉非关键的迭代hasOwnProperty,如果不这样做,则会得到警告或错误。


如何遍历HTML中的地图?它似乎根本不起作用。<div ng-repeat =“(key.value)in model.myMap”> {{key}}。</ div>
小泉

@ powerfade917它不起作用,它仅适用于数组,因为angular是一堆垃圾。但这是一个新问题,因此您将学到,角度不是一堆垃圾,但您必须将其转换为数组。请注意,由于您似乎无法区分angular和打字稿,因此您也不是编程的最高级。
peterh-恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.