Un Map di TypeScript è il Map integrato di JavaScript con chiavi e valori tipizzati: Map<string, number> associa stringhe a numeri. Crealo con new Map<K, V>(), poi usa set, get, has e delete. get restituisce V | undefined, perché la chiave potrebbe mancare.
Sono gli argomenti di tipo a rendere utile un Map in TypeScript: ogni set viene controllato e ogni get restituisce il tipo del valore. L'ultima riga è un errore di compilazione (TS2345); @ts-expect-error fa sì che il blocco venga comunque eseguito.
Questa pagina parla della collezione Map. Se cercavi array.map(), lo trovi nell'ultima sezione.
Creare un Map
I tipi arrivano dagli argomenti di tipo, dalle voci iniziali o da un'annotazione. Le voci iniziali sono un array di tuple [key, value], o qualsiasi altra cosa che le produca.
Due trappole dell'inferenza:
new Map()senza argomenti di tipo e senza voci èMap<any, any>. Niente di ciò che inserisci o estrai viene controllato. Scrivi semprenew Map<K, V>().- Voci con tipi di valore diversi non producono un'unione.
new Map([["a", 1], ["b", "x"]])è l'errore TS2769 (No overload matches this call). Scrivi il tipo:new Map<string, number | string>([...]).
get restituisce V | undefined
Un Map non può garantire che una chiave esista, quindi get ha tipo V | undefined. Con strict, devi gestire undefined prima di usare il valore come V:
index.ts(4,7): error TS2322: Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
Le soluzioni, dalla più comune alla meno comune:
TypeScript non ricorda che has ha restituito true quando in seguito chiami get. Controllare direttamente il risultato di get è più breve e sicuro. Una non-null assertion, stock.get("apples")!, zittisce l'errore ma non ti protegge se la chiave manca.
Metodi di Map e i loro tipi
| Membro | Tipo su Map<K, V> | Note |
|---|---|---|
new Map<K, V>(entries?) | Map<K, V> | entries: iterabile di [K, V] |
set(key, value) | this | Aggiunge o sostituisce; concatenabile |
get(key) | V | undefined | undefined se manca |
has(key) | boolean | |
delete(key) | boolean | true se qualcosa è stato rimosso |
clear() | void | Rimuove tutto |
size | number | Una proprietà, non un metodo |
keys(), values() | iteratori di K, V | Espandili in un array: [...map.keys()] |
entries(), for...of | iteratore di [K, V] | Ordine di inserimento |
forEach((value, key) => ...) | void | Attenzione: il valore viene prima |
Iterare un Map
Un Map si itera in ordine di inserimento. for...of sul map produce tuple [key, value], con tipo [K, V].
Impostare una chiave esistente aggiorna il valore ma ne mantiene la posizione originale nell'ordine.
Chiavi oggetto e conteggi
Qualsiasi valore può essere una chiave, compresi oggetti e array. Le chiavi si confrontano come con ===: due oggetti con lo stesso contenuto sono chiavi diverse. Un Map è anche il modo standard per contare o raggruppare elementi.
Per usare come chiave il contenuto di un oggetto, ricava invece una chiave stringa o numerica, come user.id o `${x},${y}`.
Map vs oggetto vs Record
Map<K, V> | Oggetto / Record<string, V> | |
|---|---|---|
| Tipi di chiave | qualsiasi, confrontati come con === | string (i numeri diventano stringhe), symbol |
| Tipo per chiave mancante | get restituisce V | undefined | obj[key] è V a meno che noUncheckedIndexedAccess sia attivo |
| Ordine | ordine di inserimento | in gran parte ordine di inserimento, ma le chiavi simili a interi vengono prima, in ordine crescente |
| Dimensione | map.size | Object.keys(obj).length |
| Aggiunte e rimozioni frequenti | ottimizzato per questo | non ottimizzato per questo |
| JSON | non direttamente (JSON.stringify(map) è "{}") | diretto |
| Sintassi letterale, destrutturazione | no | sì |
| Chiavi ereditate per errore | nessuna | "toString" in {} è true |
Regola pratica: un Map per una collezione le cui chiavi sono dati (id utente, parole, voci di cache) e cambiano a runtime; un tipo oggetto o Record per un insieme fisso di chiavi note e per tutto ciò che va verso o arriva da JSON. La pagina sul dictionary confronta index signature, Record e Map per le ricerche con chiavi stringa.
Convertire i Map in oggetti e JSON
Le voci di un Map non sono proprietà, quindi JSON.stringify non le vede. Converti passando per Object.fromEntries e Object.entries:
JSON.parse restituisce any, quindi as Record<...> dichiara cosa ti aspetti che siano i dati. Non è un controllo a runtime; valida il JSON non affidabile prima di fidarti di quel tipo.
Tipizzare array.map()
Molte ricerche di "typescript map" riguardano il metodo degli array, che trasforma ogni elemento e restituisce un nuovo array. Il suo tipo viene inferito dalla callback, quindi le annotazioni servono di rado:
Annotare il tipo di ritorno della callback ((u): Option => ...) è il modo più chiaro per dichiarare il tipo del risultato: una proprietà mancante o scritta male nell'oggetto restituito diventa allora un errore di compilazione nella callback.
Domande frequenti
Come si crea un Map in TypeScript?
Passa i tipi di chiave e valore al costruttore: const ages = new Map<string, number>(). Con delle voci iniziali, i tipi vengono inferiti: new Map([["ada", 36]]) è un Map<string, number>. Un new Map() senza tipi e senza voci è Map<any, any>, che disattiva il controllo, quindi dagli sempre dei tipi.
Perché Map.get restituisce undefined in TypeScript?
map.get(key) ha tipo V | undefined perché la chiave potrebbe non esserci. TypeScript non collega un map.has(key) precedente a un get successivo, quindi anche dopo has devi gestire undefined: salva il risultato e controllalo, oppure usa un valore predefinito con ??.
Che differenza c'è tra Map e oggetto in TypeScript?
Un Map accetta chiavi di qualsiasi tipo (oggetti compresi), mantiene l'ordine di inserimento, ha una size ed è fatto per aggiunte e rimozioni frequenti. Un oggetto semplice o un Record<string, V> ha solo chiavi stringa (e symbol), si serializza direttamente in JSON e supporta la sintassi letterale e la destrutturazione. Usa un Map per collezioni dinamiche con chiavi, un oggetto per forme fisse e dati JSON.
Come converto un Map in un oggetto o in JSON in TypeScript?
Object.fromEntries(map) trasforma un Map<string, V> in un oggetto semplice, che JSON.stringify può poi serializzare. JSON.stringify(map) sul Map stesso dà "{}", perché le voci di un Map non sono proprietà. L'operazione inversa è new Map(Object.entries(obj)).
Come tipizzo la callback di array.map in TypeScript?
Di solito non serve: items.map((item) => item.name) inferisce item dall'array e il tipo del risultato da ciò che restituisce la callback. Per forzare un tipo di risultato, passalo come argomento di tipo, items.map<string>(...), oppure annota il tipo di ritorno della callback.