Une Map TypeScript est la Map intégrée de JavaScript avec des clés et des valeurs typées : Map<string, number> associe des chaînes à des nombres. Créez-en une avec new Map<K, V>(), puis utilisez set, get, has et delete. get renvoie V | undefined, car la clé peut être absente.
Ce sont les arguments de type qui rendent une Map utile en TypeScript : chaque set est vérifié et chaque get renvoie le type des valeurs. La dernière ligne est une erreur de compilation (TS2345) ; @ts-expect-error permet au bloc de s'exécuter.
Cette page traite de la collection Map. Si vous cherchiez array.map(), elle est couverte dans la dernière section.
Créer une Map
Les types viennent des arguments de type, des entrées initiales ou d'une annotation. Les entrées initiales sont un tableau de tuples [key, value], ou tout autre objet qui en produit.
Deux pièges d'inférence :
new Map()sans arguments de type ni entrées est uneMap<any, any>. Rien de ce que vous y mettez ou en retirez n'est vérifié. Écrivez toujoursnew Map<K, V>().- Des entrées avec des types de valeurs différents n'infèrent pas une union.
new Map([["a", 1], ["b", "x"]])provoque l'erreur TS2769 (No overload matches this call). Écrivez le type :new Map<string, number | string>([...]).
get renvoie V | undefined
Une Map ne peut pas promettre qu'une clé existe, donc get est typé V | undefined. En mode strict, vous devez traiter le undefined avant d'utiliser la valeur comme un V :
index.ts(4,7): error TS2322: Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
Les solutions, de la plus courante à la moins courante :
TypeScript ne se souvient pas que has a renvoyé true quand vous appelez get ensuite. Vérifier directement le résultat de get est à la fois plus court et sûr. Une assertion non nulle, stock.get("apples")!, fait taire l'erreur mais ne protège de rien si la clé est absente.
Les méthodes de Map et leurs types
| Membre | Type sur Map<K, V> | Remarques |
|---|---|---|
new Map<K, V>(entries?) | Map<K, V> | entries : itérable de [K, V] |
set(key, value) | this | Ajoute ou remplace ; chaînable |
get(key) | V | undefined | undefined si absente |
has(key) | boolean | |
delete(key) | boolean | true si quelque chose a été retiré |
clear() | void | Retire tout |
size | number | Une propriété, pas une méthode |
keys(), values() | itérateurs de K, V | À étaler dans un tableau : [...map.keys()] |
entries(), for...of | itérateur de [K, V] | Ordre d'insertion |
forEach((value, key) => ...) | void | Attention : la valeur vient en premier |
Parcourir une Map
Une Map se parcourt dans l'ordre d'insertion. for...of sur la map produit des tuples [key, value], typés [K, V].
Affecter une clé existante met à jour la valeur mais conserve sa position d'origine dans l'ordre.
Clés objets et comptage
N'importe quelle valeur peut servir de clé, y compris des objets et des tableaux. Les clés sont comparées comme avec === : deux objets au contenu identique sont des clés différentes. Une Map est aussi la façon standard de compter ou de regrouper des éléments.
Pour indexer selon le contenu d'un objet, dérivez plutôt une clé string ou number, comme user.id ou `${x},${y}`.
Map vs objet vs Record
Map<K, V> | Objet / Record<string, V> | |
|---|---|---|
| Types de clés | tout, comparé comme avec === | string (les nombres deviennent des chaînes), symbol |
| Type d'une clé absente | get renvoie V | undefined | obj[key] est V sauf si noUncheckedIndexedAccess est activé |
| Ordre | ordre d'insertion | surtout l'ordre d'insertion, mais les clés de type entier viennent d'abord, dans l'ordre croissant |
| Taille | map.size | Object.keys(obj).length |
| Ajouts et suppressions fréquents | optimisée pour ça | pas optimisé pour ça |
| JSON | pas directement (JSON.stringify(map) donne "{}") | direct |
| Syntaxe littérale, déstructuration | non | oui |
| Clés héritées par accident | aucune | "toString" in {} vaut true |
Règle générale : une Map pour une collection dont les clés sont des données (identifiants d'utilisateurs, mots, entrées de cache) qui changent à l'exécution ; un type objet ou un Record pour un ensemble fixe de clés connues et pour tout ce qui va vers ou vient du JSON. La page dictionnaire compare les signatures d'index, Record et Map pour les recherches par clé string.
Convertir une Map en objet et en JSON
Les entrées d'une Map ne sont pas des propriétés, donc JSON.stringify ne les voit pas. Passez par Object.fromEntries et Object.entries :
JSON.parse renvoie any, donc le as Record<...> indique ce que les données sont censées être. Ce n'est pas une vérification à l'exécution ; validez un JSON non fiable avant de faire confiance à ce type.
Typer array.map()
Beaucoup de recherches « typescript map » visent la méthode de tableau, qui transforme chaque élément et renvoie un nouveau tableau. Son type est inféré à partir du callback, les annotations sont donc rarement nécessaires :
Annoter le type de retour du callback ((u): Option => ...) est la façon la plus claire d'indiquer le type du résultat : une propriété manquante ou mal orthographiée dans l'objet renvoyé devient alors une erreur de compilation au niveau du callback.
Questions fréquentes
Comment créer une Map en TypeScript ?
Passez les types de clé et de valeur au constructeur : const ages = new Map<string, number>(). Avec des entrées initiales, les types sont inférés : new Map([["ada", 36]]) est une Map<string, number>. Un new Map() nu, sans types ni entrées, est une Map<any, any>, ce qui désactive la vérification : donnez-lui donc toujours des types.
Pourquoi Map.get renvoie-t-il undefined en TypeScript ?
map.get(key) est typé V | undefined parce que la clé peut être absente. TypeScript ne relie pas un map.has(key) antérieur à un get ultérieur, donc même après has il faut gérer undefined : stockez le résultat et vérifiez-le, ou utilisez une valeur par défaut avec ??.
Quelle est la différence entre Map et un objet en TypeScript ?
Une Map accepte des clés de n'importe quel type (objets compris), conserve l'ordre d'insertion, possède une size, et est conçue pour des ajouts et suppressions fréquents. Un objet ordinaire ou un Record<string, V> n'a que des clés string (et symbol), se sérialise directement en JSON, et accepte la syntaxe littérale et la déstructuration. Utilisez une Map pour des collections dynamiques indexées par clé, un objet pour des formes fixes et des données JSON.
Comment convertir une Map en objet ou en JSON en TypeScript ?
Object.fromEntries(map) transforme une Map<string, V> en objet ordinaire, que JSON.stringify peut ensuite sérialiser. JSON.stringify(map) sur la Map elle-même donne "{}", car les entrées d'une Map ne sont pas des propriétés. L'inverse est new Map(Object.entries(obj)).
Comment typer le callback de array.map en TypeScript ?
En général, ce n'est pas nécessaire : items.map((item) => item.name) infère item à partir du tableau et le type du résultat à partir de ce que renvoie le callback. Pour imposer un type de résultat, passez-le comme argument de type, items.map<string>(...), ou annotez le type de retour du callback.