Um Map em TypeScript é o Map nativo do JavaScript com chaves e valores tipados: Map<string, number> mapeia strings para números. Crie um com new Map<K, V>() e depois use set, get, has e delete. get retorna V | undefined, porque a chave pode não existir.
São os argumentos de tipo que tornam um Map útil no TypeScript: todo set é verificado e todo get retorna o tipo do valor. A última linha é um erro de compilação (TS2345); @ts-expect-error mantém o bloco rodando.
Esta página trata da coleção Map. Se você procurava array.map(), ele está na última seção.
Criando um Map
Os tipos vêm de argumentos de tipo, das entradas iniciais ou de uma anotação. As entradas iniciais são um array de tuplas [key, value] ou qualquer outra coisa que as gere.
Duas armadilhas de inferência:
new Map()sem argumentos de tipo e sem entradas éMap<any, any>. Nada do que você coloca ou tira é verificado. Sempre escrevanew Map<K, V>().- Entradas com tipos de valor diferentes não inferem uma union.
new Map([["a", 1], ["b", "x"]])é o erro TS2769 (No overload matches this call). Escreva o tipo:new Map<string, number | string>([...]).
get retorna V | undefined
Um Map não pode garantir que uma chave existe, então get tem o tipo V | undefined. Com strict, você precisa lidar com o undefined antes de usar o valor como V:
index.ts(4,7): error TS2322: Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
As correções, da mais comum para a menos comum:
O TypeScript não lembra que has retornou true quando você chama get depois. Verificar direto o resultado de get é mais curto e seguro. Uma non-null assertion, stock.get("apples")!, silencia o erro, mas não protege nada se a chave não existir.
Métodos do Map e seus tipos
| Membro | Tipo em Map<K, V> | Observações |
|---|---|---|
new Map<K, V>(entries?) | Map<K, V> | entries: iterável de [K, V] |
set(key, value) | this | Adiciona ou substitui; pode ser encadeado |
get(key) | V | undefined | undefined quando a chave não existe |
has(key) | boolean | |
delete(key) | boolean | true se algo foi removido |
clear() | void | Remove tudo |
size | number | Uma propriedade, não um método |
keys(), values() | iteradores de K, V | Espalhe em um array: [...map.keys()] |
entries(), for...of | iterador de [K, V] | Ordem de inserção |
forEach((value, key) => ...) | void | Atenção: o valor vem primeiro |
Iterando um Map
Um Map é iterado na ordem de inserção. for...of sobre o map gera tuplas [key, value], com o tipo [K, V].
Definir uma chave que já existe atualiza o valor, mas mantém a posição original dela na ordem.
Chaves que são objetos e contagem
Qualquer valor pode ser chave, inclusive objetos e arrays. As chaves são comparadas como ===: dois objetos com o mesmo conteúdo são chaves diferentes. Um Map também é a forma padrão de contar ou agrupar itens.
Para usar o conteúdo de um objeto como chave, derive uma chave string ou numérica, como user.id ou `${x},${y}`.
Map vs objeto vs Record
Map<K, V> | Objeto / Record<string, V> | |
|---|---|---|
| Tipos de chave | qualquer um, comparado como === | string (números viram strings), symbol |
| Tipo de uma chave ausente | get retorna V | undefined | obj[key] é V, a menos que noUncheckedIndexedAccess esteja ativada |
| Ordem | ordem de inserção | quase sempre a de inserção, mas chaves que parecem inteiros vêm primeiro em ordem crescente |
| Tamanho | map.size | Object.keys(obj).length |
| Inserções e remoções frequentes | otimizado para isso | não otimizado para isso |
| JSON | não diretamente (JSON.stringify(map) é "{}") | direto |
| Sintaxe literal, desestruturação | não | sim |
| Chaves herdadas por acidente | nenhuma | "toString" in {} é true |
Regra prática: um Map para uma coleção cujas chaves são dados (ids de usuário, palavras, entradas de cache) e mudam em tempo de execução; um tipo de objeto ou Record para um conjunto fixo de chaves conhecidas e para tudo o que vai para JSON ou vem dele. A página de dicionário compara index signatures, Record e Map para buscas com chave string.
Convertendo Maps em objetos e JSON
As entradas de um Map não são propriedades, então JSON.stringify não as enxerga. Converta com Object.fromEntries e Object.entries:
JSON.parse retorna any, então o as Record<...> declara o que se espera que os dados sejam. Isso não é uma verificação em tempo de execução; valide JSON não confiável antes de confiar nesse tipo.
Tipando array.map()
Muitas buscas por "typescript map" se referem ao método de array, que transforma cada elemento e retorna um novo array. O tipo dele é inferido a partir do callback, então anotações raramente são necessárias:
Anotar o tipo de retorno do callback ((u): Option => ...) é a forma mais clara de declarar o tipo do resultado: uma propriedade ausente ou com nome errado no objeto retornado passa a ser erro de compilação no próprio callback.
Perguntas frequentes
Como criar um Map no TypeScript?
Passe os tipos da chave e do valor para o construtor: const ages = new Map<string, number>(). Com entradas iniciais, os tipos são inferidos: new Map([["ada", 36]]) é um Map<string, number>. Um new Map() sem tipos e sem entradas é Map<any, any>, o que desliga a verificação, então sempre informe os tipos.
Por que Map.get retorna undefined no TypeScript?
map.get(key) tem o tipo V | undefined porque a chave pode não existir. O TypeScript não liga um map.has(key) anterior a um get posterior, então mesmo depois do has você precisa tratar o undefined: guarde o resultado e verifique, ou use um valor padrão com ??.
Qual é a diferença entre Map e objeto no TypeScript?
Um Map aceita chaves de qualquer tipo (inclusive objetos), mantém a ordem de inserção, tem size e foi feito para inserções e remoções frequentes. Um objeto comum ou Record<string, V> só tem chaves string (e symbol), vira JSON diretamente e aceita sintaxe literal e desestruturação. Use Map para coleções dinâmicas com chave e objeto para formatos fixos e dados JSON.
Como converter um Map em objeto ou JSON no TypeScript?
Object.fromEntries(map) transforma um Map<string, V> em um objeto comum, que JSON.stringify consegue serializar. JSON.stringify(map) direto no Map dá "{}", porque as entradas de um Map não são propriedades. O caminho inverso é new Map(Object.entries(obj)).
Como tipar o callback de array.map no TypeScript?
Em geral não é preciso: items.map((item) => item.name) infere item a partir do array e o tipo do resultado a partir do que o callback retorna. Para forçar um tipo de resultado, passe-o como argumento de tipo, items.map<string>(...), ou anote o tipo de retorno do callback.