迭代 Typescript Map

Posted

技术标签:

【中文标题】迭代 Typescript Map【英文标题】:Iterating over 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。 有人遇到过这个问题吗?

【问题讨论】:

从 github github.com/Microsoft/TypeScript/issues/…查看这个答案 我犯了一个愚蠢的错误,在JS中,不要做map["key"] = "value",而是map.set("key", "value") 【参考方案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.from、Array.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)

【讨论】:

以上是关于迭代 Typescript Map的主要内容,如果未能解决你的问题,请参考以下文章

如何在 TypeScript 中迭代自定义文字类型?

迭代 Typescript Map

如何迭代 TypeScript 中的已知属性键?

typescript Carousel Component TS - 迭代3

typescript 专辑组件 - 迭代2

typescript 轮播组件 - 迭代1 - 文本