How to Create a Map from an Array in TypeScript

You can create a Map from an array in TypeScript by passing an array of [key, value] pairs to new Map(). For an array of objects, turn each object into a pair with map() first, and TypeScript infers the key and value types for you:

const byId = new Map(customers.map((c) => [c.id, c]));   // Map<number, Customer>

These snippets were checked with TypeScript 7.0.2 with Node.js v22.22.2 in strict mode, so the types and errors you see are what the compiler really reports.

We’ll build Maps from pairs and from objects, see what happens with duplicate keys, handle the undefined that get() can return, group items with Map.groupBy(), and count values.

Create a Map from an array of key-value pairs

new Map() accepts any iterable of two-item arrays. Type the pairs as tuples, [string, number][], and you get a Map<string, number>:

const pairs: [string, number][] = [
  ["Austin", 8.25],
  ["Denver", 8.81],
  ["Seattle", 10.35],
];
const taxRates = new Map(pairs);            // Map<string, number>
console.log(taxRates);
console.log("Denver:", taxRates.get("Denver"), "| size:", taxRates.size);

const dupes = new Map([["TX", "Austin"], ["CO", "Denver"], ["TX", "Dallas"]]);
console.log(dupes);                         // the last "TX" wins

Output:

Map(3) { 'Austin' => 8.25, 'Denver' => 8.81, 'Seattle' => 10.35 }
Denver: 8.81 | size: 3
Map(2) { 'TX' => 'Dallas', 'CO' => 'Denver' }
Command Prompt output of a TypeScript Map created from an array of city and tax rate pairs, plus duplicate keys where the last value wins
Lookups by key and size work right away. When a key repeats, the last value overwrites the earlier one.

Duplicate keys don’t throw, so check your data first if each key must be unique. Finding repeats is covered in removing duplicates from an array of objects.

Create a Map from an array of objects (keyed by id)

This is the case I use most: fast lookups by id instead of searching the array every time. Return a pair from map() and pass the result to new Map():

interface Customer {
  id: number;
  name: string;
  state: string;
}

const customers: Customer[] = [
  { id: 101, name: "Emily Clark", state: "TX" },
  { id: 102, name: "James Lee", state: "CO" },
  { id: 103, name: "Olivia Diaz", state: "FL" },
];

const byId = new Map(customers.map((c) => [c.id, c]));     // Map<number, Customer>
const nameById = new Map(customers.map((c) => [c.id, c.name] as const));

console.log(byId.get(102));
console.log(nameById);
console.log("has 104?", byId.has(104));

Output:

{ id: 102, name: 'James Lee', state: 'CO' }
Map(3) {
  101 => 'Emily Clark',
  102 => 'James Lee',
  103 => 'Olivia Diaz'
}
has 104? false
Command Prompt output of TypeScript Maps built from an array of customer objects keyed by id, with get and has lookups
One Map holds whole customer objects; the other keeps just the names. has() answers membership in constant time.

The as const keeps [c.id, c.name] a tuple instead of widening it to (string | number)[]. If you’d rather keep a plain object, a TypeScript Record type does a similar job for string keys.

Why does Map.get() return undefined in TypeScript?

get() returns V | undefined, because the key might not be there. With --strict, using the result directly is an error:

interface Customer { id: number; name: string; }
const byId = new Map<number, Customer>([[101, { id: 101, name: "Emily Clark" }]]);

const customer = byId.get(101);
console.log(customer.name.toUpperCase());

Output:

map_get_undefined.ts(5,13): error TS18048: 'customer' is possibly 'undefined'.
Command Prompt output of the TypeScript compiler error TS18048 customer is possibly undefined after Map.get
TS18048: the compiler won’t let you assume the key exists.

Check the value, or use optional chaining with a fallback:

interface Customer { id: number; name: string; }
const byId = new Map<number, Customer>([[101, { id: 101, name: "Emily Clark" }]]);

const customer = byId.get(101);
if (customer) {
  console.log(customer.name.toUpperCase());
}
console.log(byId.get(999)?.name ?? "unknown customer");

Output:

EMILY CLARK
unknown customer

Avoid the ! non-null assertion unless you’ve just called has(). It silences the compiler without protecting you at runtime. Similar checks for plain objects are in checking if a key exists in a TypeScript object.

Group array items into a Map with Map.groupBy()

Map.groupBy() (ES2024) puts items into arrays under a key you compute. TypeScript needs es2024 in lib; with an older lib the method doesn’t exist yet:

const orders = [
  { id: "A-1001", state: "TX", total: 59.99 },
  { id: "A-1002", state: "CA", total: 120.0 },
  { id: "A-1003", state: "TX", total: 35.5 },
];
const byState = Map.groupBy(orders, (o) => o.state);
console.log(byState);

Output:

map_groupby.ts(6,21): error TS2550: Property 'groupBy' does not exist on type 'MapConstructor'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2024' or later.
map_groupby.ts(6,38): error TS7006: Parameter 'o' implicitly has an 'any' type.

With --lib es2024 it compiles, and Node.js 21 or later runs it:

const orders = [
  { id: "A-1001", state: "TX", total: 59.99 },
  { id: "A-1002", state: "CA", total: 120.0 },
  { id: "A-1003", state: "TX", total: 35.5 },
];
const byState = Map.groupBy(orders, (o) => o.state);
console.log(byState);

for (const [state, list] of byState) {
  const sum = list.reduce((s, o) => s + o.total, 0);
  console.log(`${state}: ${list.length} order(s), $${sum.toFixed(2)}`);
}

Output:

Map(2) {
  'TX' => [
    { id: 'A-1001', state: 'TX', total: 59.99 },
    { id: 'A-1003', state: 'TX', total: 35.5 }
  ],
  'CA' => [ { id: 'A-1002', state: 'CA', total: 120 } ]
}
TX: 2 order(s), $95.49
CA: 1 order(s), $120.00
Command Prompt output of tsc failing on Map.groupBy with lib es2023, then compiling with lib es2024 and grouping orders by state
The same file fails with es2023 and works with es2024, grouping orders by state with totals.

On older targets, the same grouping takes a few lines with the TypeScript reduce method and map.set().

Count occurrences with a Map

Counting is the other everyday job. Read the current count with get(), default it to 0 with ??, and set it back:

const visits = ["Austin", "Denver", "Austin", "Miami", "Austin", "Denver"];

const counts = new Map<string, number>();
for (const city of visits) {
  counts.set(city, (counts.get(city) ?? 0) + 1);
}
console.log(counts);

const counts2 = visits.reduce(
  (m, city) => m.set(city, (m.get(city) ?? 0) + 1),
  new Map<string, number>(),
);
console.log([...counts2].sort((a, b) => b[1] - a[1])[0], "is the most visited");

Output:

Map(3) { 'Austin' => 3, 'Denver' => 2, 'Miami' => 1 }
[ 'Austin', 3 ] is the most visited

Because set() returns the Map itself, it also works as the accumulator inside reduce(). To turn the result back into an array for sorting or display, see converting a Map to an array in TypeScript.

Map vs object when you build from an array

NeedUse
Keys that aren’t strings (numbers, objects)Map
Frequent adds and deletes, sizeMap
Plain JSON in and outObject / Record
Fixed set of known keysObject type or Record with a union

These guides fit well with Maps:

Frequently asked questions

How do I create a Map from an array in TypeScript?

Pass an array of [key, value] pairs to new Map(). For objects, use new Map(items.map((i) => [i.id, i])).

How do I type a Map created from an array?

Usually TypeScript infers it. You can also write new Map<number, Customer>(...) or type the pairs as tuples.

What happens with duplicate keys?

The last pair with that key wins; earlier values are overwritten without an error.

Why is Map.get() possibly undefined?

The key may be missing, so the return type is V | undefined. Check the value or use ?. and ??.

Why doesn’t Map.groupBy exist in my TypeScript project?

Add es2024 (or newer) to lib in tsconfig.json, and run on Node.js 21 or later.

Where is the Map constructor documented?

See Map() constructor on MDN.