【问题标题】:Iterating over Typescript Map迭代 Typescript Map
【发布时间】:2016-10-08 12:49:00
【问题描述】:

我正在尝试迭代一个打字稿地图,但我不断收到错误,对于这样一个微不足道的问题,我还没有找到任何解决方案。

我的代码是:

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

我得到了错误:

Type 'IterableIteratorShim' 不是数组类型或字符串类型。

全栈跟踪:

 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 和 typescript 1.8.10,我的目标是 es5。 有人遇到过这个问题吗?

【问题讨论】:

标签: typescript iterator maps


【解决方案1】:

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

像这样使用它:

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

【讨论】:

  • 刚刚碰到这个。看起来 TypeScript 不尊重 map 迭代的规范,至少根据 MDN 指定的 for-of 循​​环。 .forEach 是次优的,因为你不能打破它,AFAIK
  • 不知道为什么它的价值是关键。似乎倒退了。
  • 如果我们找到了我们需要的东西,如何停止这个迭代过程?
  • @Samjones 在 foreach 中使用 return; 与在普通 for 循环中使用 continue 相同
  • @monamona 并且,请祈祷,break 的等价物是什么,因为 Samjones 明确提到 break.... 我知道的唯一方法就是拥有一个外部标记skipToEnd = false,而不是break; 放入skipToEnd = true; return 并且在函数的最开始你必须添加if (skipToEnd) return;...不是很优雅。
【解决方案2】:

如果你不是很喜欢嵌套函数,你也可以遍历键:

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

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

【讨论】:

  • 如何在 html 中遍历地图?它似乎根本不起作用。
    {{key}}。
  • @powerfade917 它不起作用,它仅适用于数组,因为 angular 是一堆垃圾。但是将此作为一个新问题提出,您将了解到,角度不是一堆垃圾,但您必须将其转换为数组。请注意,您也不是编程的佼佼者,因为您似乎无法区分 Angular 和 typescript。
【解决方案3】:

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

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

【讨论】:

  • 转换映射是一项非常耗性能的操作,而不是解决本质上只是编译器隐藏语言核心部分的问题的正确方法。只需 &lt;any&gt;-cast 映射以使用 for-of 对其进行迭代。
  • 当心:我认为上面的@Kilves 建议将 Map 转换为“any”是一种优雅的解决方法。当我这样做时,代码编译并运行没有任何抱怨,但 Map 实际上并没有被迭代——循环的内容从未执行过。这里提出的Array.from() 策略确实对我有用。
  • 我也试过了,它对我也不起作用,考虑到它 ES6 的一部分并且应该在大多数浏览器上“正常工作”,这就更加愚蠢了。但我猜我们的 angular 霸主在 zone.js 中使用了一些神奇的 mumbo jumbo 让它不起作用,因为他们讨厌 ES6。叹息。
  • @Kilves foreach 不支持完全异步/等待
  • @Han 我知道,这就是为什么我说 for-of,而不是 foreach。
【解决方案4】:

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

【讨论】:

  • 上面给出的es6版本没有在严格模式下编译。
  • 这个问题是关于打字稿,而不是普通的js
【解决方案5】:

我正在使用最新的 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);
}

【讨论】:

  • 您能否确认您首先必须在您的tsconfig.json 中设置"downlevelIteration": true
  • 我没有设置downlevelIteraton,但是我的目标是es2017
  • 我不能为 Map 元素执行此操作吗?编译器说它不是类型或字符串类型的数组。
  • 这在 2.8 上对我不起作用 - 我得到 Type 'Map&lt;K, V&gt;' is not an array type or a string type.
  • 这对我不起作用。我应该使用任何“lib”吗?
【解决方案6】:

根据TypeScript 2.3 release notes on "New --downlevelIteration"

for..of statements、Array Destructuring 和Spread 元素在Array、Call 和New 表达式中支持ES5/E3 中的Symbol.iterator(如果在使用--downlevelIteration 时可用)

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

有了这个,你可以写for (let keyval of myMap) {...}keyval的类型将被自动推断。


为什么默认关闭?根据 TypeScript 贡献者@aluanhaddad

它是可选的,因为它对生成代码的大小有非常显着的影响,并可能对所有可迭代对象(包括数组)的使用性能产生影响。

如果您可以针对 ES2015("target": "es2015" in tsconfig.jsontsc --target ES2015)或更高版本,启用 downlevelIteration 是不费吹灰之力,但如果您针对 ES5/ES3,您可以进行基准测试以确保迭代器支持不会影响性能(如果影响,您可能会更好地使用Array.from 转换或forEach 或其他一些解决方法)。

【讨论】:

  • 在使用 Angular 时启用此功能是否可行或危险?
【解决方案7】:

使用Array.fromArray.prototype.forEach()arrow functions

遍历

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

【讨论】:

  • 不知道为什么,我有像 Map 这样的地图。除 Array.from(myMap.values()).forEach(value => console.log(value));. 之外,上述方法均无效
【解决方案8】:

这对我有用。打字稿版本:2.8.3

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

【讨论】:

  • 我通过将 Object.entries(myMap) 更改为 myMap.entries() 来实现此功能。我喜欢这个答案,因为它避免了 .forEach 调用的错误处理陷阱。
  • 值得注意的是,如果 tsconfig 中的 targetes5,则会引发错误,但 es6 可以正常工作。你也可以在定位es6时只做for (const [key, value] of myMap)
【解决方案9】:

只是在 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)

完成!

【讨论】:

    【解决方案10】:

    这对我有用。

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

    【讨论】:

    • 这样,键将始终是字符串
    【解决方案11】:

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

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

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

      "downlevelIteration": true,
    

    【讨论】:

    • 这个功能是在 TypeScript 2.3 中引入的。 TypeScript 1.8.10 出现问题
    • 如果不能使用“downlevelIteration”,可以使用:const projected = Array.from(myMap).map(...);
    【解决方案12】:

    在 Typescript 3.5 和 Angular 8 LTS 上,需要按如下方式转换类型:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-01
      • 2019-09-15
      • 2021-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-20
      相关资源
      最近更新 更多