Iterasi di atas Peta Ketikan

135

Saya mencoba untuk mengulangi peta ketikan tetapi saya terus mendapatkan kesalahan dan saya belum bisa menemukan solusi untuk masalah sepele seperti itu.

Kode saya adalah:

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

Dan saya mendapatkan Error:

Jenis 'IterableIteratorShim <[string, boolean]>' bukan jenis larik atau jenis string.

Jejak Tumpukan Penuh:

 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)

Saya menggunakan angular-cli beta5 dan typescript 1.8.10 dan target saya adalah es5. Adakah yang punya masalah ini?

mwe
sumber
4
Lihat jawaban ini dari github github.com/Microsoft/TypeScript/issues/…
yurzui

Jawaban:

212

Anda bisa menggunakan Map.prototype.forEach((value, key, map) => void, thisArg?) : voidsebagai gantinya

Gunakan seperti ini:

myMap.forEach((value: boolean, key: string) => {
    console.log(key, value);
});
rinukkusu
sumber
15
Baru saja mengalami ini. Sepertinya TypeScript tidak menghormati spesifikasi untuk iterasi peta, setidaknya menurut MDN yang menetapkan perulangan for-of. .forEachkurang optimal, karena Anda tidak dapat memecahkannya, AFAIK
Samjones
14
tidak tahu mengapa nilainya lalu kuncinya. Sepertinya mundur.
Paul Rooney
@PaulRooney mungkin seperti itu untuk selaras Array.prototype.map.
Ahmed Fasih
1
Bagaimana cara menghentikan proses iterasi ini jika kami menemukan apa yang kami butuhkan?
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];
}
Oded Breiner
sumber
1
Versi es6 yang diberikan di atas tidak dikompilasi dalam mode ketat.
Stephane
Terima kasih tuan yang baik.
Kitanga Nday
36

Cukup gunakan Array.from()metode untuk mengubahnya menjadi fileArray :

myMap : Map<string, boolean>;
for(let key of Array.from( myMap.keys()) ) {
   console.log(key);
}
6qat
sumber
5
Mengonversi peta adalah operasi yang sangat haus kinerja dan bukan cara yang tepat untuk memecahkan masalah yang pada dasarnya hanya penyusun yang menyembunyikan bagian inti dari bahasa tersebut. Cukup- <any>siarkan peta untuk mengulanginya dengan for-of.
Kilves
1
Waspadalah: Saya pikir saran @Kilves di atas untuk mengubah Peta menjadi "any" adalah solusi yang bagus. Ketika saya melakukannya, kode dikompilasi dan dijalankan tanpa keluhan, tetapi Peta sebenarnya tidak diiterasi - konten loop tidak pernah dieksekusi. The Array.from()strategi yang diusulkan di sini melakukan pekerjaan untuk saya.
mactyr
Saya mencobanya juga, itu juga tidak berhasil untuk saya, yang bahkan lebih bodoh mengingat ini adalah bagian dari ES6 dan seharusnya "berfungsi" di sebagian besar browser. Tapi saya kira tuan sudut kami menggunakan beberapa omong kosong ajaib di zone.js untuk membuatnya tidak berfungsi, karena mereka membenci ES6. Mendesah.
Kilves
28

Menggunakan fungsi Array.from , Array.prototype.forEach () , dan panah :

Iterasi di atas kunci :

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

Iterasi nilai :

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

Iterasi entri :

Array.from(myMap.entries()).forEach(entry => console.log('Key: ' + entry[0] + ' Value: ' + entry[1]));
Tobold
sumber
2
Tidak yakin mengapa, saya memiliki peta seperti Map <String, CustomeClass>. tidak ada metode di atas yang berfungsi kecuali Array.from (myMap.values ​​()). forEach (value => console.log (value)) ;.
Rajashree Gr
27

Ini berhasil untuk saya. Versi TypeScript: 2.8.3

for (const [key, value] of Object.entries(myMap)) { 
    console.log(key, value);
}
Debashish Sen
sumber
7
Saya mendapatkan ini untuk bekerja dengan mengubah Object.entries (myMap) menjadi hanya myMap.entries (). Saya menyukai jawaban ini karena menghindari kesalahan penanganan kesalahan panggilan .forEach.
berakhir
2
Perlu dicatat bahwa jika Anda targetdi tsconfigadalah es5ini melempar kesalahan, tapi dengan es6karya-karya dengan benar. Anda juga dapat melakukannya for (const [key, value] of myMap)saat menargetkanes6
Benjamin Vogler
16

Sesuai catatan rilis TypeScript 2.3 tentang "Baru --downlevelIteration" :

for..of statements, Array Destructuring, dan elemen Spread di Array, Call, dan ekspresi baru mendukung Symbol.iterator di ES5 / E3 jika tersedia saat menggunakan --downlevelIteration

Ini tidak diaktifkan secara default! Tambahkan "downlevelIteration": trueke Anda tsconfig.json, atau berikan --downlevelIterationbendera ke tsc, untuk mendapatkan dukungan iterator penuh.

Dengan ini, Anda dapat menulis for (let keyval of myMap) {...}dan keyvaltipe akan disimpulkan secara otomatis.


Mengapa ini dimatikan secara default? Menurut kontributor TypeScript @aluanhaddad ,

Ini opsional karena memiliki dampak yang sangat signifikan pada ukuran kode yang dihasilkan, dan berpotensi pada kinerja, untuk semua penggunaan iterable (termasuk array).

Jika Anda dapat menargetkan ES2015 ( "target": "es2015"dalam tsconfig.jsonatau tsc --target ES2015) atau lebih baru, mengaktifkannya downlevelIterationtidak perlu dipikirkan lagi, tetapi jika Anda menargetkan ES5 / ES3, Anda dapat melakukan tolok ukur untuk memastikan dukungan iterator tidak memengaruhi kinerja (jika ya, Anda mungkin lebih baik off dengan Array.fromkonversi atau forEachatau solusi lain).

Ahmed Fasih
sumber
apakah ini baik atau berbahaya untuk mengaktifkan ini saat menggunakan Angular?
Simon_Weaver
9

Ini berhasil untuk saya.

Object.keys(myMap).map( key => {
    console.log("key: " + key);
    console.log("value: " + myMap[key]);
});
Jason Slobotski
sumber
2
Dengan ini, kuncinya akan selalu menjadi string
Ixx
8

Saya menggunakan TS dan node terbaru (masing-masing v2.6 dan v8.9) dan saya dapat melakukan:

let myMap = new Map<string, boolean>();
myMap.set("a", true);
for (let [k, v] of myMap) {
    console.log(k + "=" + v);
}
lazieburd
sumber
Dapatkah Anda mengkonfirmasi bahwa Anda pertama kali harus set "downlevelIteration": truedi Anda tsconfig.json?
Ahmed Fasih
3
Saya belum downlevelIteratonmenetapkan, es2017namun target saya .
lazieburd
Tidak dapatkah saya melakukan ini untuk elemen Map <string, CustomClass []>? compiler mengatakan itu bukan array tipe atau tipe string.
Rajashree Gr
ini tidak bekerja untuk saya di 2.8 - Saya mengertiType 'Map<K, V>' is not an array type or a string type.
Simon_Weaver
3

Anda juga bisa menerapkan metode peta larik ke iterable Map.entries ():

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

Juga, seperti disebutkan dalam jawaban lain, Anda mungkin harus mengaktifkan iterasi tingkat bawah di tsconfig.json Anda (di bawah opsi kompiler):

  "downlevelIteration": true,
cham
sumber
Fitur ini diperkenalkan di TypeScript 2.3. Masalah terjadi dengan TypeScript 1.8.10
mwe
Jika Anda tidak dapat menggunakan "downlevelIteration", Anda dapat menggunakan:const projected = Array.from(myMap).map(...);
Efrain
1

Hanya penjelasan sederhana untuk menggunakannya dalam dokumen HTML.

Jika Anda memiliki Map of types (key, array) maka Anda menginisialisasi array dengan cara ini:

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

Dan untuk mengulanginya, Anda membuat array dari nilai kunci.

Gunakan saja sebagai array seperti pada:

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

Kemudian, dalam HTML, Anda dapat menggunakan:

*ngFor="let key of keys"

Di dalam loop ini, Anda baru saja mendapatkan nilai array dengan:

this.cityShop.get(key)

Selesai!

Sophie C Musikal
sumber
1

Pada Typecript 3.5 dan Angular 8 LTS, diharuskan untuk menggunakan tipe sebagai berikut:

for (let [k, v] of Object.entries(someMap)) {
    console.log(k, v)
}
Constantin Konstantinidis
sumber
-1

Jika Anda tidak terlalu menyukai fungsi bersarang, Anda juga dapat melakukan iterasi pada tombol:

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

Catatan, Anda harus memfilter iterasi non-kunci dengan hasOwnProperty, jika Anda tidak melakukan ini, Anda akan mendapatkan peringatan atau kesalahan.

peterh - Kembalikan Monica
sumber
bagaimana cara mengulang peta di html? sepertinya tidak berhasil sama sekali. <div ng-repeat = "(key, value) di model.myMap"> {{key}}. </div>
Shinya Koizumi
@ powerfade917 Ini tidak bekerja, ini hanya bekerja untuk array karena sudut adalah tumpukan sampah. Tapi tanyakan ini sebagai pertanyaan baru dan Anda akan belajar, bahwa angular bukanlah tumpukan sampah, tapi Anda harus mengubahnya menjadi sebuah array. Perhatikan, Anda juga bukan yang teratas dari pemrograman, karena Anda tampaknya tidak mampu membedakan antara angular dan skrip.
peterh - Pulihkan Monica