Welcome! Today, we will explore creating a simple address book application using TypeScript's Map
. This task will help you understand how to manipulate Map
in TypeScript, focusing on adding, retrieving, and deleting entries. By the end of this lesson, you'll have a solid grasp of these fundamental operations while ensuring data integrity through the type annotations that TypeScript provides.
In this task, we will implement three methods to manage our address book, using type annotations to ensure code reliability:
addContact(name: string, phoneNumber: string): boolean
: Adds a new contact. Returnsfalse
if the contact already exists; otherwise, it adds the contact and returnstrue
. In this task, let's assume phone numbers do not change, so it's not allowed to overwrite the existing contact's number.getContact(name: string): string | undefined
: Retrieves the phone number for a givenname
. Returnsundefined
if the contact does not exist.deleteContact(name: string): boolean
: Deletes a contact with the givenname
. Returnstrue
if the contact exists and is deleted,false
otherwise.
Let's break down each method in detail in the next sections.
Before we begin implementing the methods in our address book, we need to set up our TypeScript class that will hold the contacts using a Map
.
Here's how to set up the initial structure:
TypeScript1class AddressBook { 2 contacts: Map<string, string>; 3 4 constructor() { 5 this.contacts = new Map<string, string>(); 6 } 7} 8
In this initial setup:
- We define the
AddressBook
class with acontacts
property, which is aMap
that holds the name of the contact as the key and the phone number as the value. - We initialize the
contacts
property in the constructor, ensuring each instance ofAddressBook
starts with an empty map.
This method adds a new contact to the address book with the given name
and phoneNumber
. If the contact already exists, it returns false
. Otherwise, it adds the contact and returns true
.
Question: Why do you think we need to check if the contact already exists?
Answer: To avoid duplicating existing entries. Also, if a contact with the same name already exists, we shouldn't allow overwriting its phone number in this method, as it's only for creation.
Here is the method implementation:
TypeScript1addContact(name: string, phoneNumber: string): boolean { 2 if (this.contacts.has(name)) { 3 return false; 4 } 5 this.contacts.set(name, phoneNumber); 6 return true; 7}
In this method:
- We use type annotations such as
name: string
andphoneNumber: string
to ensure that inputs adhere to specified types. - We verify if the contact already exists using
if (this.contacts.has(name))
. - If it exists, we return
false
. - If it doesn't exist, we add it to our
Map
and returntrue
.
This method retrieves the phone number associated with a given name
. If the contact does not exist, it returns undefined
.
Question: What do we gain by returning undefined
when a contact doesn't exist?
Answer: It provides a clear indicator that the contact is not in the address book, allowing us to handle such cases gracefully.
Here is the method implementation:
TypeScript1getContact(name: string): string | undefined { 2 return this.contacts.get(name); 3}
In this method:
- Type annotations
name: string
for the parameter andstring | undefined
for the return type ensure that we expect a string or an undefined value returned.
This method deletes a contact with the given name
. If the contact exists and is deleted, it returns true
. If the contact does not exist, it returns false
.
Here is the method implementation:
TypeScript1deleteContact(name: string): boolean { 2 return this.contacts.delete(name); 3}
The deleteContact
method attempts to remove a contact with the specified name
by utilizing the delete
method of the Map
, which inherently returns a boolean. This boolean indicates success (true
) if the contact was found and removed or failure (false
) if no such contact existed.
Let's consolidate everything we've learned into the final implementation of our AddressBook
class, and provide a simple example of how you might use it.
Here is the complete implementation of the AddressBook
class with all three methods:
TypeScript1class AddressBook { 2 contacts: Map<string, string>; 3 4 constructor() { 5 this.contacts = new Map<string, string>(); 6 } 7 8 addContact(name: string, phoneNumber: string): boolean { 9 if (this.contacts.has(name)) { 10 return false; 11 } 12 this.contacts.set(name, phoneNumber); 13 return true; 14 } 15 16 getContact(name: string): string | undefined { 17 return this.contacts.get(name); 18 } 19 20 deleteContact(name: string): boolean { 21 return this.contacts.delete(name); 22}
Here's an example demonstrating how to use the AddressBook
class:
TypeScript1const myAddressBook = new AddressBook(); 2 3// Adding contacts 4console.log(myAddressBook.addContact('Alice', '123-456-7890')); // true 5console.log(myAddressBook.addContact('Bob', '987-654-3210')); // true 6console.log(myAddressBook.addContact('Alice', '111-111-1111')); // false, already exists 7 8// Retrieving contacts 9console.log(myAddressBook.getContact('Alice')); // '123-456-7890' 10console.log(myAddressBook.getContact('Charlie')); // undefined 11 12// Deleting contacts 13console.log(myAddressBook.deleteContact('Bob')); // true 14console.log(myAddressBook.deleteContact('Charlie')); // false
This example demonstrates how to add, retrieve, and delete contacts using the implemented methods in the AddressBook
class.
Maps are particularly efficient for managing an address book due to several reasons, enhanced by TypeScript's strong typing:
- Efficient Lookups and Insertions: Maps provide average O(1) time complexity for lookups, insertions, and deletions. This means managing contacts is very fast, even with a large number of them.
- Preservation of Insertion Order: Maps maintain the order of entries according to their insertion sequence, which might be useful for displaying contacts in the order they were added.
- Type Safety with Keys and Values: TypeScript enforces type safety, ensuring all keys and values in the
Map
strictly follow the defined types, reducing bugs caused by unintended type mismatches.
In this lesson, we implemented a type-safe address book using TypeScript's Map
, covering three key methods: addContact
, getContact
, and deleteContact
. The use of Map
provided efficient O(1) average time complexity for lookups, insertions, and deletions, as well as maintenance of insertion order, enhancing the usability and performance of our address book application. Through these methods, we've demonstrated how TypeScript can enforce type safety while interacting with Map
, providing reliable and efficient data management.
Now that you're familiar with these fundamental operations, let's dive into the practice exercises to reinforce your understanding and skills!