Map in TypeScript: una collezione chiave-valore tipizzata
Map in TypeScript
Map in TypeScript: tipizzare, iterare e salvare una Map | We.Inc
Tipizza una Map<K, V> in TypeScript, iterala, convertila in JSON e ritorno, e scegli tra Map, Record e un oggetto semplice. Prova una Map dal vivo nel browser.
In TypeScript una Map è la normale Map di JavaScript con i tipi per chiavi e valori: new Map<string, number>(). Le chiavi possono essere qualsiasi valore, le entry tornano nell'ordine in cui sono state aggiunte la prima volta, size le conta e get restituisce V | undefined. JSON.stringify non serializza una Map, quindi convertila prima.
I metodi di Map e cosa restituisce TypeScript
Chiamata
Cosa fa
Tipo che ottieni (Map<string, number>)
map.set(k, v)
Aggiunge o aggiorna una entry
Map<string, number> (concatenabile)
map.get(k)
Legge un valore
number | undefined
map.has(k)
Verifica una chiave
map.delete(k)
Rimuove una entry
boolean (true se esisteva)
Conta le entry
for (const [k, v] of map)
Itera in ordine di inserimento
k: string, v: number
Il playground qui sotto è una vera Map in esecuzione nel tuo browser. Aggiungi, aggiorna ed elimina entry e osserva tre cose: l'ordine che le entry mantengono, cosa riporta size, e la differenza tra fare lo stringify della Map stessa e di una sua copia convertita.
Scrivi una chiave e un numero, poi premi Imposta per aggiungere o aggiornare quella entry.
Premi Elimina per rimuovere la chiave scritta nella casella, oppure Svuota per svuotare la Map.
Leggi l'elenco delle entry, che segue l'ordine di iterazione della Map stessa.
Confronta le due righe JSON per capire perché una Map va convertita prima di salvarla o inviarla.
Specifica gli argomenti generici quando crei una Map vuota. new Map() da solo è Map<any, any>, e ogni lettura successiva perde il suo tipo.
Controlla has() o confronta get() con undefined prima di usare un valore. Una non-null assertion nasconde il caso in cui la chiave manca davvero.
Le chiavi oggetto vengono confrontate per riferimento. Due oggetti con gli stessi campi sono due chiavi diverse, quindi usa una stringa id quando intendi lo stesso record.
Per tenere una Map in localStorage, salva JSON.stringify([...map]) e ricostruiscila con new Map(JSON.parse(text)). L'array di coppie mantiene le chiavi non stringa e l'ordine.
Domande frequenti
Come dichiaro il tipo di una Map in TypeScript?
Passa i tipi di chiave e valore come argomenti generici: const prices = new Map<string, number>(). Per un campo o un parametro, scrivi il tipo come Map<string, number>, oppure ReadonlyMap<string, number> quando la funzione deve solo leggerla.
Perché map.get() ha undefined nel suo tipo?
Perché il compilatore non può sapere quali chiavi sono nella Map in un dato momento. get è tipizzato come V | undefined, quindi restringi con un controllo if, un fallback ?? o un test has() prima di trattare il valore come V.
Perché JSON.stringify(map) restituisce {}?
Una Map tiene le sue entry in uno slot interno, non come proprietà dell'oggetto, quindi JSON vede un oggetto vuoto. Convertila prima: Object.fromEntries(map) per chiavi stringa, oppure [...map] per un array di coppie che funziona con qualsiasi tipo di chiave.
Meglio una Map o un Record?
Usa un Record per un insieme fisso di chiavi con nome e per dati che vanno e vengono da JSON. Usa una Map quando le entry si aggiungono e si tolgono mentre l'app è in esecuzione, quando le chiavi sono numeri o oggetti, o quando conta l'ordine di inserimento.
Aggiornare una chiave la sposta in fondo?
No. Impostare una chiave esistente ne cambia il valore ma mantiene la sua posizione originale. Per spostarla in fondo, elimina la chiave e impostala di nuovo.
Map, Record e oggetto semplice
Un oggetto semplice eredita da Object.prototype, quindi nomi come constructor sono già presenti, e le sue chiavi sono sempre stringhe o symbol. Una Map parte vuota, accetta qualsiasi valore come chiave e riporta il numero di entry tramite size.
Record è un tipo, non un contenitore. Descrive un oggetto semplice, quindi tutto ciò che vale per gli oggetti si applica anche a lui a runtime, compreso il supporto nativo a JSON che a una Map manca.
Come vengono confrontate le chiavi
Map confronta le chiavi con la regola SameValueZero. Il numero 1 e la stringa "1" sono chiavi diverse, NaN corrisponde a NaN, e un oggetto corrisponde solo a sé stesso. Un oggetto semplice trasformerebbe 1 in "1" e unirebbe le due.
Questo rende la Map la cache naturale per valori indicizzati da un elemento DOM, una funzione o un oggetto richiesta, casi in cui un oggetto avrebbe bisogno di un id stringa inventato.
Tipizzare le Map nelle firme delle funzioni
Accetta ReadonlyMap<K, V> nelle funzioni che leggono soltanto. Toglie set, delete e clear dal tipo, così la firma stessa dice a chi chiama che la sua Map non verrà modificata.
Quando costruisci una Map da un array di coppie, TypeScript deduce i tipi dalle coppie. Aggiungi un generico esplicito quando l'array potrebbe essere vuoto o quando le coppie mescolano tipi che vuoi tenere separati.
Ricette con Map tipizzate
Contare le parole con una Map
Il fallback ?? gestisce la prima occorrenza di una parola, ed è per questo che get che restituisce number | undefined è utile invece che fastidioso.
Salvare una Map come JSON e ricaricarla
Un array di coppie mantiene ogni entry e il suo ordine. Object.fromEntries è la scelta più leggibile quando tutte le chiavi sono stringhe.
Accettare una Map in sola lettura
Dentro total, chiamare prices.set sarebbe un errore di compilazione, quindi chi chiama può passare la sua Map senza una copia difensiva.
Playground Map dal vivo
Chiave
Valore (numero)
Imposta
Elimina
Svuota
Ripristina
Entry in ordine di iterazione
La Map è vuota.
size: {n}
Aggiunto "{v}".
Eliminato "{v}".
"{v}" non è nella Map, quindi delete ha restituito false.