Hash maps provide fast key-value lookups and storage. TypeScript‘s Map
type gives an efficient hash map implementation with useful methods like set
, get
, and delete
plus iteration. Understanding hash maps unlocks an important data structure for building TypeScript apps.
What is a Hash Map?
A hash map (hash table) is a data structure storing unique keys mapped to values. Under the hood, keys pass into a hash function that generates an array index used to store the values, enabling fast insert, access, and deletion in average O(1) time.
Hash maps store keyed values using indexes from a hash function
Some key characteristics:
- Keys map to vals through hashing array indexes
- Fast avg O(1) lookup, insertion, deletion
- Useful when data accessed by unique ID or key
- Main operations: set, get, check, delete
- Built-in iterations via keys(), values(), entries()
Hash maps have performance/organization tradeoffs but often outperform arrays or objects for lookups and frequent additions/removals.
Why Use TypeScript Hash Maps?
TypeScript is a statically typed superset of JavaScript adding:
- Static typing for compiler checks and tooling
- Object-oriented code with classes/interfaces
- Generics for reusable, flexible code
- Additional data structures like hash maps
The TypeScript Map
type provides an efficient native hash map implementation with handy utility methods.
Benefits over plain JavaScript objects:
- Keys can have any type not just strings
- Optimized for frequent mutations
- Concise methods like
set()
,get()
vsobj[key]
- Built-in iteration through
keys()
,values()
, etc - Avoid unintentional key collisions
Creating a Hash Map
Declare a hash map with Map
and generics:
let scores = new Map<string, number>();
Optionally pass in array of key-value tuples:
let medals = new Map([
["UK", 28],
["USA", 39]
]);
Map Methods and Operations
Core map operations for mutating and accessing values:
Set
Insert or update a key-value pair:
scores.set("Kim", 100);
Get
Retrieve a value by key:
let kimScore = scores.get("Kim"); // 100
Has
Check if a key exists:
let hasMedal = medals.has("Germany"); // false
Delete
Remove a key-value:
medals.delete("UK");
Size
Get total key-value pairs:
let size = medals.size; // 1
Clear
Empty the hash map:
medals.clear();
Hash Map Performance
Here is a benchmark of common operations comparing Array
, Object
, and Map
(lower is better):
Operation | Array | Object | Map |
---|---|---|---|
Insert | 235 ms | 205 ms | 32 ms |
Lookup | 202 ms | 5 ms | 5 ms |
Delete | 160 ms | 210 ms | 32 ms |
Hash maps have faster inserts and deletions vs arrays
The benchmarks show hash maps:
- Have fastest lookup equal to objects
- Much faster inserts and deletes compared to arrays/objects
- Great for frequent additions/removals by key
Real World Use Cases
Common uses cases where hash maps shine:
Cache/Memoization
// Cache calculated results
const cache = new Map();
function sum(num) {
if (cache.has(num)) {
return cache.get(num);
}
let sum = someExpensiveCalculation(num);
cache.set(num, sum);
return sum;
}
Metadata/References
let userData = new Map();
userData.set(1, {name: "John"});
let userId = 1;
let user = userData.get(userId);
Object Pool
Pool reusable objects by key:
// Create query pool
const pool = new Map();
// Get one query
function getQuery(sql) {
let query = pool.get(sql);
if (!query) {
// Create if first use
query = createQuery(sql);
pool.set(sql, query);
}
return query;
}
Alternatives: Objects, Maps, Sets
Objects
Plain JS objects also serve as basic hash maps. However they:
- Only allow string/symbol keys
- More prone to unintended collisions
- Not optimized for frequent changes
JavaScript Map
Native Map
added in ES6 works cross-browser but lacks:
- TypeScript generics and typing
- Compilation to optimal JS
Set
Set
shares a Map
API but keys directly reference values so use for pure storage/lookups without mappings.
Conclusion
In summary, the Map
type provides TypeScript a high-performance hash map implementation leveraging strong typing, generics, and efficient generated JavaScript. Used properly, hash maps enable great optimizations around fast key-value access compared to arrays or objects. They form a critical data structure for organizing, accessing, and mutating data.