2016-06-08 23 views
27

Sto tentando di eseguire un'iterazione su una mappa dattiloscritta, ma continuo a ricevere errori e non sono riuscito a trovare alcuna soluzione per un problema così insignificante.Iterating over Typescript Map

Il mio codice è:

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

E ottengo l'errore:

Type 'IterableIteratorShim<[string, boolean]>' is not an array type or a string type.

completa dello stack:

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)

sto usando beta5 angolare-cli e dattiloscritto 1.8 .10 e il mio obiettivo è es5. Qualcuno ha avuto questo problema?

+4

Vedere questa risposta da github https://github.com/Microsoft/TypeScript/issues/3164#issuecomment-104443321 – yurzui

+0

Grazie. Anche un po 'strano che stiano ancora discutendo di questo problema. – mwe

risposta

46

Si potrebbe utilizzare Map.prototype.forEach((value, key, map) => void, thisArg?) : void invece

usare in questo modo:

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

Mi sono imbattuto in questo. Non sembra che TypeScript rispetti le specifiche per l'iterazione della mappa, almeno secondo [MDN] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) che specifica un ciclo for-of. '.forEach' è sub-ottimale, dal momento che non è possibile romperlo, AFAIK – Samjones

+3

Le mie esperienze mostrano che .for Semplicemente non funziona. Ignora l'intero ciclo, non succede nulla. – peterh

+0

Come stampare questo in un'espressione angolare? – Lobato

1

Se non piace funzioni nidificate, è anche possibile scorrere i tasti:

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

Nota, devi filtrare le iterazioni senza chiave con lo hasOwnProperty, se non lo fai, ricevi un avviso o un errore.

+0

come eseguire iterazioni sulla mappa in html? non sembra funzionare affatto.

{{key}}.
powerfade917

+0

@ powerfade917 Non funziona, funziona solo per gli array perché angolare è una pila di spazzatura. Ma chiedilo come una nuova domanda e così imparerai, quell'angolare non è una pila di spazzatura, ma devi convertirlo in un array. Nota, anche tu non sei il top della programmazione, perché sei apparentemente incapace di distinguere tra angolare e dattiloscritto. – peterh

12

Basta usare Array.from() per convertirlo in un array:

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

Funziona anche per altri tipi come chiavi, non solo per 'stringa' e la chiave non viene convertita in' stringa'. – kcpr

4
for (let entry of Array.from(map.entries())) { 
    let key = entry[0]; 
    let value = entry[1]; 
} 
0

Sto utilizzando le più recenti TS e nodo (rispettivamente v2.6 e v8.9) e posso fare:

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

Puoi confermare che hai prima impostato '" downlevelIteration ": true' nel tuo' tsconfig.json'? –

+1

Non ho impostato 'downlevelIteraton', il mio obiettivo è' es2017' comunque. – lazieburd

0

Per il TypeScript 2.3 release notes on "New --downlevelIteration":

for..of statements , Array Destructuring, and Spread elements in Array, Call, and New expressions support Symbol.iterator in ES5/E3 if available when using --downlevelIteration

Questo non è abilitato di default! Aggiungi "downlevelIteration": true al numero tsconfig.json oppure passa il flag --downlevelIteration a tsc, per ottenere il supporto completo per l'iteratore.

Con questo in posizione, è possibile scrivere for (let keyval of myMap) {...} e il tipo di keyval sarà dedotto automaticamente.


Perché è disattivato per impostazione predefinita? Secondo dattiloscritto collaboratore @aluanhaddad,

It is optional because it has a very significant impact on the size of generated code, and potentially on performance, for all uses of iterables (including arrays).

Se è possibile destinare ES2015 ("target": "es2015" in tsconfig.json o tsc --target ES2015) o versione successiva, consentendo downlevelIteration è un gioco da ragazzi, ma se ci si rivolge ES5/ES3, si potrebbe punto di riferimento per assicurati che il supporto dell'iteratore non influenzi le prestazioni (se lo fa, potresti stare meglio con la conversione Array.from o forEach o qualche altra soluzione alternativa).