- Published on
TypeScript: Using Maps, a complete guide
Table of Contents
In TypeScript, the Map object is a collection of key-value pairs that allows you to store and retrieve data based on a key. It is similar to the JavaScript object, but with some added functionality and better type safety.
Let's start by creating a Map object:
const myMap = new Map()
This creates an empty Map object. You can also pass an iterable object to the constructor to initialize the Map:
const myMap = new Map([
['key1', 'value1'],
['key2', 'value2'],
['key3', 'value3']
])
Now that we have a Map, let's look at some methods that we can use.
Setting and Getting Values
To set a value in a Map, use the set
method:
myMap.set('key', 'value')
To get a value from a Map, use the get
method:
const value = myMap.get('key')
Checking if a Key Exists
To check if a key exists in a Map, use the has
method:
if (myMap.has('key')) {
console.log('Key exists!')
} else {
console.log('Key does not exist.')
}
Removing a Key-Value Pair
To remove a key-value pair from a Map, use the delete
method:
myMap.delete('key')
Emptying the Map
To remove all key-value pairs from a Map, use the clear
method:
myMap.clear()
Iterating Over a Map
To iterate over a Map, use the forEach
method:
myMap.forEach((value, key) => {
console.log(`${key}: ${value}`)
})
You can also use a for...of
loop to iterate over a Map:
for (const [key, value] of myMap) {
console.log(`${key}: ${value}`)
}
Using Objects as Values
The usage of a Map with number/string
as keys and Objects
as values is commonly used.
interface Member {
fullName: string
subscriptionID?: number
}
const member1: Member = { fullName: 'John Smith', subscriptionID: 123 }
const member2: Member = { fullName: 'Mike Doe' }
const members = new Map<number, Member>()
members.set(1, member1)
members.set(2, member2)
console.log(members.get(1)) // { fullName: 'John Smith', subscriptionID: 123 }
console.log(members.get(2)) // { fullName: 'Mike Doe' }
Using Objects as Keys
In JavaScript, objects can be used as keys in a Map. However, this can lead to unexpected behavior due to object reference equality.
In TypeScript, you can use a custom type as a key by defining an interface and using it as the type parameter for the Map:
interface Member {
fullName: string
subscriptionID?: number
}
const member1: Member = { fullName: 'John Smith', subscriptionID: 123 }
const member2: Member = { fullName: 'Mike Doe' }
const member3: Member = { fullName: 'John Smith', subscriptionID: 123 }
const members = new Map<Member, string>()
members.set(member1, 'Premium')
members.set(member2, 'Basic')
console.log(members.get(member1)) // Premium
console.log(members.get(member2)) // Basic
console.log(members.has(member1)) // ✅ true
console.log(members.has(member2)) // ✅ true
console.log(members.has(member3)) // ❌ false
console.log(members.has({ fullName: 'Mike Doe' })) // ❌ false
In this example, we're using a Member
interface as the key type for the Map. We can then set values for each member object and retrieve them using the same object reference.
The get()
method of the Map object uses strict equality (===)
to compare the key passed in to each key in the map.
Caveat
When using objects as keys, the has method only works with the exact same object that was used as a key. Even if an object has the same properties as another object, it will not be considered a key in the Map unless it is the same object instance.
putIfAbsent
Utils: javalike To check if a similar member already exists in the members Map before inserting it, you can modify the set method to first check if a key with the same properties already exists in the Map, and only insert the new key-value pair if it doesn't.
interface Member {
fullName: string
subscriptionID?: number
}
const member1: Member = { fullName: 'John Doe', subscriptionID: 123 }
const member2: Member = { fullName: 'Jane Smith' }
const members = new Map<Member, string>()
members.set(member1, 'Premium')
const putIfAbsent = (map: Map<Member, string>, newMember: Member, value: string) => {
const isUniqueKey = Array.from(map.keys()).find(existingMember => {
return isEqual(existingMember, newMember) //or use lodash's isEqual
})
if (!isUniqueKey) {
map.set(newMember, value)
}
}
const isEqual = (member1: Member, member2: Member): boolean => {
return member1.fullName === member2.fullName && member1.subscriptionID === member2.subscriptionID
}
putIfAbsent(members, member1, 'Premium') // doesn't add a new key-value pair
putIfAbsent(members, member2, 'Basic') // adds a new key-value pair
console.log(members.size) // 2
console.log(members.get(member1)) // 'Premium'
console.log(members.get(member2)) // 'Basic'
Note that this approach only works if the objects have the same properties in the same order.
If the objects have additional properties or the properties are in a different order, this method will not detect them as similar.
In that case, you may need to write a custom comparison function that checks each property individually.
Using Map in TypeScript can make your code more type-safe and easier to work with.
By understanding the basic methods and concepts of Map, you can take advantage of its powerful features in your projects.