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とtypescript 1.8.10を使用していますが、ターゲットはes5です。誰かがこの問題を抱えていますか?


4
このgithubのからの回答を参照してくださいgithub.com/Microsoft/TypeScript/issues/...
yurzui

回答:


210

Map.prototype.forEach((value, key, map) => void, thisArg?) : void代わりに使用できます

次のように使用します。

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

15
ちょうどこれに遭遇しました。TypeScriptは、少なくともfor-ofループを指定するMDNに従って、マップ反復の仕様を尊重しているようには見えません。.forEachあなたはそれを壊すことができないので、最適ではありません、AFAIK
Samjones

14
なぜその価値が重要なのか。後方に見える。
Paul Rooney

@PaulRooneyそれはおそらくと調和するようなものですArray.prototype.map
Ahmed Fasih

1
必要なものが見つかった場合、この反復プロセスを停止するにはどうすればよいですか?
19:44のJavaRunner

36

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バージョンは、strictモードでコンパイルされていません。
ステファン

あなたの親切な先生に感謝。
キタンガNday

36

ただ、使用Array.from()に変換する方法をArray

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

5
マップの変換は非常にパフォーマンスを必要とする操作であり、本質的に言語のコア部分を隠すコンパイラだけの問題を解決する正しい方法ではありません。<any>マップをキャストするだけでfor-ofで反復できます。
キルベス

1
注意:上記の@KilvesのMapを「any」にキャストするという提案は、エレガントな回避策だと思いました。私がそれをしたとき、コードはコンパイルされ、文句なしに実行されましたが、マップは実際には繰り返されませんでした-ループのコンテンツは決して実行されませんでした。Array.from()ここで提案されている戦略は、私のために仕事をしました。
mactyr

私も試してみましたが、私にとっても機能しませんでした。ES6の一部であり、ほとんどのブラウザーで「正常に動作する」はずなので、それも愚かなことです。しかし、私たちの角張った君主たちは、zone6.jsでいくつかの魔法のマンボジャンボを使用して動作しないようにしていると思います。ES6が嫌いだからです。はぁ。
キルベス2018年

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 2018

27

これでうまくいきました。TypeScriptバージョン:2.8.3

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

7
Object.entries(myMap)をmyMap.entries()だけに変更することで、これを機能させました。.forEach呼び出しのエラー処理の落とし穴を回避できるので、私はこの答えが好きです。
2018

2
targetin tsconfiges5これの場合はエラーがスローされますが、with es6は正しく動作することに注意してください。for (const [key, value] of myMap)ターゲティングするときにも実行できますes6
ベンジャミンヴォ

16

パー「新しいの活字体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 2018

9

これでうまくいきました。

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

2
これにより、キーは常に文字列になります
Ixx

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か?
Ahmed Fasih

3
私はdownlevelIteraton設定していませんが、私の目標はそうes2017です。
lazieburd

Map <string、CustomClass []>要素に対してこれを行うことはできませんか?コンパイラは型または文字列型の配列ではないと言います。
Rajashree Gr 2018

これは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ドキュメントで使用するための簡単な説明です。

タイプ(キー、配列)のマップがある場合は、次のように配列を初期化します。

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>
小泉真也2017

@ powerfade917これは機能しません。角度はゴミの山なので、配列に対してのみ機能します。しかし、これを新しい質問として尋ねてください。そうすれば、その角度はゴミの山ではありませんが、配列に変換する必要があります。また、angularとtypescriptを区別することができないように見えるため、あなたはプログラミングのトップではありません。
peterh-モニカを2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.