Why You Should Use Maps in JavaScript and TypeScript Instead of Arrays

Published on

5 min read

Categories associated to this post are: Node JS TypeScript

In JavaScript and TypeScript, we often reach for arrays by default to store collections of data. While arrays are versatile and efficient for certain types of operations, there are times when another data structure, Map, can be more effective. This post will dive into the benefits of Map, how it differs from arrays, and why you might want to use it.

What Is a Map?

A Map in JavaScript is a collection of key-value pairs, where keys can be of any type—primitive values, objects, or even functions. This flexibility is a key differentiator from objects, which typically use strings or symbols as keys.

Map properties at a glance:

  • Ordered collection (preserves insertion order).
  • Keys can be any data type.
  • Efficient for lookups and deletion operations.
  • Size property for quick access to the number of items.

Why Choose Map Over Arrays?

In arrays, we’re generally limited to numeric indexing. If you find yourself managing a collection of data where you want to associate each item with a unique key, then arrays might not be the best tool for the job. Here are some specific cases where Map is superior:

  1. Better Lookups and Deletions: Maps provide efficient, constant-time complexity for lookups, insertions, and deletions by key, unlike arrays where these operations often require searching or shifting elements.
  2. Flexible Keys: Maps allow any data type as keys, which can be very useful for creating complex data associations without stringifying keys as you would in an object.
  3. Preserving Order: While objects do not guarantee key order, Maps maintain the insertion order of keys, making iteration predictable.

How to Use Map in JavaScript and TypeScript

Creating and managing Maps in JavaScript and TypeScript is straightforward. Let’s look at some code examples to illustrate the main features.

Basic Usage of Map

TypeScript
const myMap = new Map();
 
// Adding key-value pairs
myMap.set('name', 'Bai Fengxi');
myMap.set('age', 33);
 
// Retrieving values
console.log(myMap.get('name')); // Bai Fengxi
console.log(myMap.get('age'));  // 33
 
// Checking if a key exists
console.log(myMap.has('age')); // true
 
// Removing a key-value pair
myMap.delete('age');
console.log(myMap.has('age')); // false
 
// Checking the size
console.log(myMap.size); // 1

Using Complex Keys

Unlike arrays, Maps allow for non-primitive keys, which makes them highly versatile:

TypeScript
const objKey = { id: 1 };
const funcKey = () => 'key function';
 
myMap.set(objKey, 'Object Key');
myMap.set(funcKey, 'Function Key');
 
console.log(myMap.get(objKey));    // Object Key
console.log(myMap.get(funcKey));   // Function Key

Iterating Over a Map

Maps provide easy methods to iterate over entries, which can be more convenient than handling array indices.

TypeScript
myMap.set('country', 'England');
myMap.set('city', 'London');
 
// Iterating over keys
for (const key of myMap.keys()) {
  console.log(key);
}
 
// Iterating over values
for (const value of myMap.values()) {
  console.log(value);
}
 
// Iterating over entries
for (const [key, value] of myMap.entries()) {
  console.log(`${key}: ${value}`);
}

Real-World Example: Caching with a Map

Maps are ideal for caching, where you associate a unique identifier with some precomputed data. Let’s look at a simple example where we use a Map to cache expensive calculations:

TypeScript
const calculationCache = new Map<number, number>();
 
const expensiveCalculation = (n: number): number => {
  if (calculationCache.has(n)) {
    console.log(`Returning cached value for ${n}`);
 
    return calculationCache.get(n)!;
  }
 
  // Simulate an expensive calculation
  const result = n * n;
 
  calculationCache.set(n, result);
 
  return result;
};
 
console.log(expensiveCalculation(5)); // 25
console.log(expensiveCalculation(5)); // Returns cached result 25

Using a Map here improves performance by eliminating the need to recompute values that have already been calculated.

Maps vs. Arrays in Key-Value Pair Storage

If you need to store and retrieve data with unique keys, Map is a better choice than an array of objects or key-value pairs. Arrays will require searching each entry to find a specific key, which is slower and less efficient than using Map’s direct lookup.

TypeScript
// Using an array of objects
const dataArray = [{ key: 'name', value: 'Bai Fengxi' }, { key: 'age', value: 33 }];
const ageEntry = dataArray.find(entry => entry.key === 'age');
 
console.log(ageEntry ? ageEntry.value : 'Not found'); // 33
 
// Using a Map for direct access
const dataMap = new Map([['name', 'Bai Fengxi'], ['age', 33]]);
 
console.log(dataMap.get('age')); // 33

Typing Maps in TypeScript

In TypeScript, you can use generic types to narrow down the types of keys and values in a Map. This allows you to leverage TypeScript’s type-checking capabilities, making your code safer and more predictable.

TypeScript
// Defining a Map with specific key-value types
const userRoles: Map<string, string> = new Map();
 
// Adding entries
userRoles.set('Bai Fengxi', 'admin');
userRoles.set('Zhao Lusi', 'user');
 
// Type-safe retrieval
const role = userRoles.get('Bai Fengxi'); // Type is string | undefined

TypeScript also supports more complex types as keys or values. For instance, you could use an interface or union type to ensure only specific keys or values are used.

TypeScript
type User = {
  id: number;
  name: string;
};
 
const userPermissions: Map<User, string[]> = new Map();
const user: User = { id: 1, name: 'Bai Fengxi' };
 
userPermissions.set(user, ['read', 'write']);

This type safety can prevent errors at compile time, which is especially useful when working with larger codebases.

Browser and Node.js Support for Maps

Maps were introduced in ECMAScript 2015 (ES6) and are supported by all modern browsers and environments. Here’s a quick summary:

  • Node.js: Support for Maps has been available since Node.js version 0.12 (2015). Any modern version of Node will have full support for Maps.
  • Browsers: Maps are supported in all major browsers, including Chrome, Firefox, Safari, and Edge, from versions released around 2015. This broad support means Maps are safe to use in virtually all environments without the need for polyfills.

Final Thoughts

Choosing the right data structure can make a big difference in the clarity and performance of your code. When you need to store key-value pairs with unique keys, Map provides several advantages over arrays:

  • Efficient lookups and deletions.
  • Flexibility with key types.
  • Predictable iteration order.

With this in mind, Map is often a better choice than arrays for scenarios requiring efficient data lookups by key. Experiment with it in your codebase, and you’ll likely find that it simplifies and improves your data handling!

Share on social media platforms.