TypeScript Map: A Typed Key-Value Collection

In TypeScript a Map is the ordinary JavaScript Map with types for its keys and values: new Map<string, number>(). Keys can be any value, entries come back in the order they were first added, size counts them, and get returns V | undefined. JSON.stringify does not serialize a Map, so convert it first.

Map methods and what TypeScript returns
CallDoesType you get (Map<string, number>)
map.set(k, v)Adds or updates an entryMap<string, number> (chainable)
map.get(k)Reads a valuenumber | undefined
map.has(k)Checks a keyboolean
map.delete(k)Removes an entryboolean (true if it existed)
map.sizeCounts entriesnumber
for (const [k, v] of map)Loops in insertion orderk: string, v: number

Updated

The playground below is a real Map running in your browser. Add, update and delete entries and watch three things: the order entries keep, what size reports, and the difference between stringifying the Map itself and stringifying a converted copy.

Live Map playground

Entries in iteration order (size: 3)

  1. tea: 3
  2. cake: 5
  3. juice: 4
JSON.stringify(map) // {}
JSON.stringify(Object.fromEntries(map)) // {"tea":3,"cake":5,"juice":4}

Typed Map recipes

Count words with a Map

The ?? fallback handles the first sighting of a word, which is why get returning number | undefined is helpful rather than annoying.

function countWords(text: string): Map<string, number> {
  const counts = new Map<string, number>();
  for (const word of text.toLowerCase().split(/\s+/).filter(Boolean)) {
    counts.set(word, (counts.get(word) ?? 0) + 1);
  }
  return counts;
}

countWords("to be or not to be"); // Map { "to" => 2, "be" => 2, "or" => 1, "not" => 1 }

Save a Map as JSON and load it back

An array of pairs keeps every entry and its order. Object.fromEntries is the readable choice when every key is a string.

const stock = new Map<string, number>([["tea", 3], ["cake", 5]]);

const asPairs = JSON.stringify([...stock]);              // '[["tea",3],["cake",5]]'
const asObject = JSON.stringify(Object.fromEntries(stock)); // '{"tea":3,"cake":5}'

const restored = new Map<string, number>(JSON.parse(asPairs));
const fromObject = new Map<string, number>(Object.entries(JSON.parse(asObject)));

Accept a read-only Map

Inside total, calling prices.set would be a compile error, so callers can pass their Map without a defensive copy.

function total(prices: ReadonlyMap<string, number>, cart: string[]): number {
  let sum = 0;
  for (const item of cart) sum += prices.get(item) ?? 0;
  return sum;
}

Map, Record and a plain object

A plain object inherits from Object.prototype, so names such as constructor are already there, and its keys are always strings or symbols. A Map starts empty, accepts any value as a key and reports its entry count through size.

Record is a type, not a container. It describes a plain object, so everything above about objects applies to it at runtime, including native JSON support that a Map lacks.

How keys are matched

Map compares keys with the SameValueZero rule. The number 1 and the string "1" are different keys, NaN matches NaN, and an object only matches itself. A plain object would turn 1 into "1" and merge the two.

That makes a Map the natural cache for values keyed by a DOM element, a function or a request object, cases where an object would need an invented string id.

Typing Maps in function signatures

Accept ReadonlyMap<K, V> in functions that only read. It removes set, delete and clear from the type, so the signature itself tells callers their Map will not be changed.

When you build a Map from an array of pairs, TypeScript infers the types from the pairs. Add an explicit generic when the array could be empty or when the pairs mix types you want kept apart.

How it works

  1. Type a key and a number, then press Set to add or update that entry.
  2. Press Delete to remove the key in the key box, or Clear to empty the Map.
  3. Read the entries list, which is the Map's own iteration order.
  4. Compare the two JSON lines to see why a Map needs converting before you save or send it.

Tips

Frequently asked questions

How do I declare the type of a Map in TypeScript?

Pass the key and value types as generic arguments: const prices = new Map<string, number>(). For a field or parameter, write the type as Map<string, number>, or ReadonlyMap<string, number> when the function should only read it.

Why does map.get() return undefined in its type?

Because the compiler cannot know which keys are in the Map at a given moment. get is typed as V | undefined, so you narrow with an if check, a ?? fallback or a has() test before treating the value as V.

Why does JSON.stringify(map) give {}?

A Map keeps its entries in an internal slot, not as object properties, so JSON sees an empty object. Convert first: Object.fromEntries(map) for string keys, or [...map] for an array of pairs that survives any key type.

Should I use a Map or a Record?

Use a Record for a fixed set of named keys and for data that goes to and from JSON. Use a Map when entries come and go while the app runs, when keys are numbers or objects, or when insertion order matters.

Does updating a key move it to the end?

No. Setting an existing key changes its value but keeps its original position. To move it to the end, delete the key and set it again.

Related: TypeScript Record type, Loops in TypeScript, TypeScript data types, TypeScript vs JavaScript, JavaScript loops compared.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap