Map and Set Types in TypeScript
Map and Set are typed collections that track keys and unique values. Learn how to type Map<K, V> and Set<T>, how they differ from objects and arrays, and common mistakes.
TypeScript Map and Set types are typed collection classes that TypeScript enhances with generic type parameters. A Map is a key-value store where both the key and value have types. A Set is a collection of unique values where every element has a single type.
Unlike plain objects, Map keys can be any type -- strings, numbers, objects, or even other Maps. Unlike arrays, a Set automatically prevents duplicate values and provides fast membership checking. Both classes exist at runtime and are not erased by the compiler.
Typing a Set
A Set is typed with one generic parameter -- the type of values it stores. Use the Set generic syntax, which is similar to how you type an Array with a single type parameter.
let names: Set<string> = new Set(["Ada", "Linus", "Grace"]);TypeScript infers the element type from the initial values, so the explicit annotation is often optional. This declaration produces the same type as the one above:
let names = new Set(["Ada", "Linus", "Grace"]);TypeScript infers that names is a Set<string>. Every method that adds or returns elements respects this type.
The add method enforces the element type. You can only add values that match the declared type:
let scores = new Set([95, 87, 91]);
scores.add(100);
scores.add("ninety");The first call succeeds because 100 is a number. The second call is a compiler error because a string does not match the number element type.
Argument of type 'string' is not assignable to parameter of type 'number'.The has method checks membership and returns a boolean. The compiler does not care what type you check -- has always returns true or false -- but the check is only meaningful for the declared type. Iterating a Set with a for-of loop gives you each element with its correct type:
let colors = new Set(["red", "green", "blue"]);
for (let color of colors) {
console.log(color.toUpperCase());
}Color is typed as string inside the loop because the Set element type is string. You can use string methods directly without any type guard.
Typing a Map
A Map is typed with two generic parameters: the key type and the value type. The syntax is Map with the key type first, then the value type in angle brackets.
let users: Map<number, string> = new Map([
[1, "Ada"],
[2, "Linus"],
]);TypeScript infers both type parameters from the initial entries, so the annotation is optional if you initialise the Map with values. Without initial values, annotate both type parameters so the compiler knows what to expect.
The set method enforces both the key and value types. Every call must match the declared types for both arguments:
let ages = new Map<string, number>();
ages.set("Ada", 30);
ages.set("Linus", 55);
ages.set(1, 25);The first two calls succeed. The third call is a compiler error because the key must be a string.
The get method returns the value type or undefined, because the key might not exist in the Map. This is the same pattern as array index access:
let ages = new Map<string, number>();
ages.set("Ada", 30);
let age = ages.get("Ada");
let missing = ages.get("Unknown");TypeScript types age as number | undefined and missing as number | undefined. You must check for undefined before using the value as a number. For more on narrowing pattern, see type narrowing basics in TypeScript.
Iterating a Map gives you key-value pairs as tuples. Each entry is typed as [KeyType, ValueType]:
let config = new Map<string, boolean>();
config.set("darkMode", true);
config.set("notifications", false);
for (let [key, value] of config) {
console.log(`${key}: ${value}`);
}The destructured key is typed as string and value is typed as boolean. You get full type safety through every iteration method -- forEach, keys, values, and entries all respect the Map's type parameters.
When to use Map and Set vs alternatives
Map and Set solve specific problems that objects and arrays handle poorly. The decision tree helps you pick the right structure:
| Use case | Best choice |
|---|---|
| Unique values, fast existence check | Set |
| Key-value storage, non-string keys | Map |
| Key-value storage, string keys only, small datasets | Object |
| Ordered list with duplicates allowed | Array |
| Fixed-length, per-position types | Tuple |
Maps shine when you need non-string keys or want to track insertion order explicitly. Sets shine when duplicate removal or fast membership testing is the primary operation. For a detailed comparison of all collection types, see choose between array tuple record map and set.
Common mistakes
The most common mistake is forgetting that Map's get method returns undefined when a key is not found. Always check the result before using it, or provide a fallback value with the nullish coalescing operator.
Another common mistake is creating an empty Map or Set without type parameters. Without initial values to infer from, the compiler uses loose defaults that disable checking. Always annotate empty collections:
let untyped = new Map();
let typed: Map<string, number> = new Map();The first line produces Map<any, any>, which accepts any key or value with no checking. The second line locks the key and value types before anything is added.
The same rule applies to an empty Set. Annotate it with the element type you intend, instead of leaving TypeScript to infer an any-typed set from nothing.
Rune AI
Key Insights
- Type a Map with Map<K, V> where K is the key type and V is the value type.
- Type a Set with Set<T> where T is the element type.
- TypeScript infers Map and Set types from the initial values, same as arrays.
- Map and Set exist at runtime and are not erased unlike many TypeScript types.
- Use Map when you need non-string keys; use Set when you need automatic duplicate removal.
Frequently Asked Questions
What is the difference between Set and Array in TypeScript?
Can I use objects as Map keys in TypeScript?
Are Map and Set types erased at runtime?
Conclusion
Map and Set are typed collection classes that exist at runtime with full type safety from TypeScript's generic parameters. Use Set for unique-value collections and Map for key-value stores with any key type. The compiler tracks element types through every add, get, has, and iteration operation.
More in this topic
TypeScript Compiler Explained
The TypeScript compiler (tsc) turns .ts files into .js files while checking types. Learn what it does, how to use it, and how it fits your workflow.
Set Up ESLint for TypeScript
Install and configure ESLint with typescript-eslint to catch bugs and enforce consistent code style in your TypeScript project.
Pick Utility Type in TypeScript
Pick creates a new type by selecting only the properties you name from an existing type. Use it to build focused types for specific views, API responses, or function parameters.