Maps are a useful data structure in many programming languages. They allow you to store key-value pairs and quickly lookup values by their associated key.
In TypeScript, maps have some additional benefits over regular JavaScript maps:
- Type safety for keys and values
- Iterability
- Additional utility methods
In this comprehensive guide, you‘ll learn:
- What are maps in TypeScript
- Why maps are useful
- How to create maps in TypeScript
- Using the Map constructor
- Using an interface
- Methods and properties of maps
- When to use maps vs other data structures
- Examples of using maps
So let‘s dive in!
What are Maps in TypeScript?
A map in TypeScript is an object that stores key-value pairs, similar to maps in other languages. The keys and values can be of any type.
Some key characteristics of maps in TypeScript:
- Keys are unique – The same key cannot occur more than once in the map
- Keys and values have consistent types – Keys must all be one type and values another type
- Entries are ordered based on insertion order
- Size can grow or shrink dynamically
- Inherits from Iterable – Can use for..of loops
- Methods for common operations like setting, getting, deleting entries
The Map class in TypeScript enforces type safety for the key-value pairs. This helps catch errors during development that might otherwise crop up during runtime.
Why Use Maps in TypeScript?
There are several reasons why using maps in TypeScript can be beneficial:
1. Type Safety
TypeScript maps ensure all keys are of one type and all values of another type. This prevents bugs from inserting inconsistent types.
2. Faster Lookup
Lookup of values by key is very fast, approaching O(1) time complexity.
3. Flexible Keys
Nearly any data type in JavaScript can be used as keys, including functions, objects, classes. Even NaN and undefined can be keys.
4. Convenient Syntax
The set(), get() and other methods provide a clean syntax for working with map entries.
5. Iterability
You can use for..of loops directly on maps, unlike regular JavaScript objects.
So in summary, maps provide type safety with high performance lookup and flexibility.
Creating Maps in TypeScript
There are a couple approaches for creating maps in TypeScript:
- Using the Map constructor
- Using an interface
Let‘s look at each method.
Map Constructor
The easiest way to create a map is by using the Map constructor:
const map = new Map<string, number>();
This creates a new map with string typed keys and number typed values.
We can initialize the map with values by passing in a 2D array:
const map = new Map<string, number>([
["key1", 1],
["key2", 2]
]);
The Map constructor takes care of enforcing the types. If we tried to incorrectly insert non-matching types:
map.set(1, "value"); // Error
We would get a type error during compilation.
Overall the Map constructor provides a simple way to create maps with type safety.
Interface Syntax
Another way to create maps is by using an interface:
interface StringNumberMap {
[key: string]: number;
}
const map: StringNumberMap = {};
Here we first define an interface specifying the key is a string and value is a number.
Then we create the object and specify it implements the interface.
We can initialize and use the map similarly:
map["key1"] = 1;
map["key2"] = 2;
The interface approach has some additional flexibility. For example we can easily extract out reusable map types:
interface Map<T, U> {
[key: T]: U;
}
type StringNumberMap = Map<string, number>;
But overall, the Map constructor approach tends to be used more often for simplicity.
Map Methods and Properties in TypeScript
Now that we know how to create maps in TypeScript, let‘s explore some of the useful methods and properties available.
set()
Sets a new key-value pair in the map:
map.set(‘key3‘, 3);
get()
Retrieves the value associated with a key:
const val = map.get(‘key3‘); // 3
has()
Returns true if the key exists:
const has = map.has(‘key3‘); // true
delete()
Removes an entry by key:
map.delete(‘key3‘);
clear()
Removes all entries from map:
map.clear();
size
Current number of key-value pairs:
const len = map.size;
keys()
Returns an iterable of keys:
for (let key of map.keys()) {
// ...
}
values()
Returns iterable of values:
for (let value of map.values()) {
// ...
}
entries()
Returns iterable of [key, value] tuples:
for (let [key, value] of map.entries()) {
// ...
}
So maps have a full set of methods for mutating and accessing entries.
When to Use Maps vs Other Data Structures
TypeScript also includes other data structures like arrays, sets, and regular objects. When might maps be more appropriate to use than alternatives?
Map vs Array
- Use a map when you need fast key-based lookup
- Use an array when you need ordered indexing
Map vs Set
- Use a map for storing key-value pairs
- Use a set for storing unique values
Map vs Object
- Use a map if keys can be non-strings
- Use objects for pure string-based lookup
So in summary:
- Map – Fast key-value lookup
- Array – Ordered list
- Set – Unique values
- Object – String-based lookup table
Choose based on the main operations you need to perform.
Examples of Maps in TypeScript
Let‘s look at some detailed use cases and examples of leveraging maps in TypeScript.
Map of Favorite Programming Languages
Let‘s store a map of developers and their favorite programming languages:
interface DeveloperMap {
[developer: string]: string;
}
const favorites: DeveloperMap = {};
favorites["Sara"] = "Python";
favorites["Tali"] = "JavaScript";
favorites["Nate"] = "Rust";
function getFavorite(name: string) {
return favorites[name];
}
console.log(getFavorite("Tali")); // JavaScript
The DeveloperMap interface encodes the structure of the data. We can easily lookup favorites by developer name.
Word Count Map
Here is an example of building a simple word count utility using a map:
function wordCount(text: string) {
const counts = new Map<string, number>();
text.split(‘ ‘).forEach(word => {
if (counts.has(word)) {
counts.set(word, counts.get(word)! + 1);
} else {
counts.set(word, 1);
}
});
return counts;
}
console.log(wordCount("the cat is in the hat"));
// Map(4) {"the" => 2, "cat" => 1, "is" => 1, "hat" => 1}
This splits text into words and counts each occurrence using the map.
Map Implementation of Sets
Since TypeScript maps provide lookup in O(1) time, we can leverage them to build performant set implementations:
class NumericSet {
private values = new Map<number, boolean>();
add(x: number) {
this.values.set(x, true);
}
has(x: number) {
return this.values.has(x);
}
}
const set = new NumericSet();
set.add(5);
console.log(set.has(5)); // true
This custom NumericSet class wraps a TypeScript map. We use the presence of the key in the map to represent membership in the set.
This allows efficient O(1) has() and add() operations.
Caching/Memoization
A common use case for maps is caching or memoizing expensive function calls:
function fib(n: number) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
const cache = new Map<number, number>();
function memoFib(n: number) {
if (cache.has(n)) {
return cache.get(n)!;
}
const result = fib(n);
cache.set(n, result);
return result;
}
console.log(memoFib(10)); // cached fast lookup
Here we store previous fibonacci number lookups in the cache map. Accessing cache values using get() and set() is faster than recomputing.
This technique works well for many recursive or expensive functions.
Conclusion
Maps are a versatile data structure in TypeScript with many use cases. The key advantages they provide are:
- Type safety
- Fast key-value lookup
- Flexible key types
- Helper methods like set(), get(), etc
In this guide we covered:
- The basics of TypeScript maps
- Creating maps via the constructor and interfaces
- Common map operations and methods
- Comparing maps to other data structures
- Examples like caches, word counts, and more
So next time you need to associate data or cache expensive operations, consider leveraging TypeScript‘s handy Map type.


