web-dev-qa-db-fra.com

Itération sur une carte TypeScript

J'essaie de parcourir une carte TypeScript, mais je continue à avoir des erreurs et je ne trouve pas encore de solution pour un problème aussi trivial.

Mon code est:

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

Et je reçois l'erreur:

Le type 'IterableIteratorShim <[string, boolean]>' 'n'est pas un type de tableau ou un type de chaîne.

Trace de pile complète:

 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)

J'utilise angular-cli beta5 et TypeScript 1.8.10 et ma cible est es5. Quelqu'un a t-il eu ce problème?

82
mwe

Vous pouvez utiliser Map.prototype.forEach((value, key, map) => void, thisArg?) : void à la place

Utilisez-le comme ceci:

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

Utilisez simplement la méthode Array.from () pour le convertir en tableau:

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

Utilisation de Array.from , Array.prototype.forEach () , et fonctions de flèche :

Itérez sur les touches :

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

Itérez sur les valeurs :

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

Itérez sur les entrées :

Array.from(myMap.entries()).forEach(entry => console.log('Key: ' + entry[0] + ' Value: ' + entry[1]));
17
Tobold

Cela a fonctionné pour moi. Version TypeScript: 2.8.3

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

Selon le Notes de version de TypeScript 2.3 sur "New --downlevelIteration" :

Les éléments for..of statements, Array Destructuring et Spread dans les expressions Array, Call et New prennent en charge Symbol.iterator dans ES5/E3, si cette option est disponible avec --downlevelIteration.

Ceci n'est pas activé par défaut! Ajoutez "downlevelIteration": true à votre tsconfig.json ou passez le drapeau --downlevelIteration à tsc, pour obtenir le support complet des itérateurs.

Avec ceci en place, vous pouvez écrire for (let keyval of myMap) {...} et le type de keyval sera automatiquement déduit.


Pourquoi est-ce désactivé par défaut? Selon le contributeur TypeScript @ aluanhaddad ,

Il est facultatif car il a un impact très important sur la taille du code généré, et potentiellement sur les performances, pour toutes les utilisations de iterables (y compris les tableaux).

Si vous pouvez cibler ES2015 ("target": "es2015" dans tsconfig.json ou tsc --target ES2015) ou une version ultérieure, l'activation de downlevelIteration est une évidence, mais si vous ciblez ES5/ES3, Il se peut que vous effectuiez des tests pour vous assurer que la prise en charge des itérateurs n’affectera pas les performances (le cas échéant, il serait peut-être préférable de procéder à la conversion de Array.from ou à forEach ou à une autre solution de contournement).

13
Ahmed Fasih

es5

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

es6

for (let [key, value] of map) {
    console.log(key, value);
}
11
Oded Breiner

J'utilise les derniers TS et nœuds (v2.6 et v8.9 respectivement) et je peux faire:

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

Cela a fonctionné pour moi.

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

Explication simple à faire à partir de HTML si vous avez une carte de types (clé, tableau):

J'initialise le tableau de cette façon:

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

Et pour itérer dessus, je crée un tableau à partir de valeurs de clé: - utilisez-le simplement comme tableau avec: keys = Array.from (this.cityShop.keys ());

Ensuite, en HTML, je peux utiliser:

*ngFor="let key of keys"

À l'intérieur de ce noyau, je viens d'obtenir la valeur du tableau avec this.cityShop.get (clé)

Et fait!

1
Sophie C Musical

Si vous n'aimez pas vraiment les fonctions imbriquées, vous pouvez également parcourir les clés:

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

Notez que vous devez filtrer les itérations sans clé avec hasOwnProperty. Si vous ne le faites pas, vous obtenez un avertissement ou une erreur.

0
peterh