Building a Phone Book Application with Typescript and React
Tags: react, typescript, javascript
Published: 2023-03-27 16:52:49

A phone book is a directory used to store and organize contact information.

In this article, we will be developing a phonebook application using TypeScript and React. 
TypeScript is a typed superset of JavaScript that allows us to catch errors at compile-time

Our phone book application will allow users to add, edit, and delete contacts.

By the end of this article, you will have a fully functional phone book application built with TypeScript and React.

Here is how the final application will look  like
 
![Final Application](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2pqws2z2r9powvpiiuqs.PNG)

View [Demo Here](https://phonebook-appp.netlify.app/)

We will be using `vite` to setup our application. Vite is a build tool that is specifically designed for modern web development.

**Note:** Ensure that Node.js version 14.18+ is installed on your system

You can download Node.js from the official website [here](https://nodejs.org), and npm will be installed automatically with Node.js.

Firstly, navigate to the directory where you want to develop your application and scaffold your application with Vite. We can do this by running the following command:

`npm create vite@latest`

This would ask you for the project name, framework, and variant.

– For project name, you can enter phonebook

– For framework, select React from the list of options

– And for variant, select TypeScript.

When its done, navigate into your project folder by running the command `cd phonebook` then run the command
`npm install` to install all required dependencies and then  `npm run dev` to start your application.

You can open your project on Visual Studio code.
Now let's install the dependencies we will need for this application.

Open the command line or bash on your project directory and run the command:
`npm install bootstrap@5.2.3 react-bootstrap@2.7.0 react-icons@4.7.1`

### Styling the application:

To add styling to our phonebook application, open the index.css file existing in your project folder, clear-off the existing styles and add the following content:
{% gist https://gist.github.com/jamesoyanna/eeafe64467e785668a3ad878468672be file=index.css %}

Next, you can access the main.tsx file in your project folder and place the import statement for the bootstrap CSS before the import statement for index.css, as shown below:
```
import 'bootstrap/dist/css/bootstrap.min.css';
import './index.css'
```

Inside your `src` folder, create a new folder. Name it `components`. Create a new file, call it `Header.tsx` and add the following content to it.
{% gist https://gist.github.com/jamesoyanna/db7afb9a37519256689b08cb66bf4b3b file=Header.tsx %}

Here, we import the "FC" (Functional Component) type from the 'react'. 

We then define the `Header` component as a function component. The ": FC" part after "Header" specifies that the component is of type "FC", which is a shorthand for `"React.FunctionComponent"`. This type is used to indicate that the component is a function that returns `JSX`.

The function itself returns a JSX element, which in this case is a header element with an h1 element inside it.
You can now test the application by run this command `npm run dev`.
If every thing works fine, you should see this page display on your browser:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5w248hwekbzl6uhrje8f.PNG)

Now let's create the form that would enable us to take input from users.

Create a new file in the `components`. Name it `ContactForm.tsx` and add the following code to it.

{% gist https://gist.github.com/jamesoyanna/2daf40ddc90ffccee0aeae9c7c5792a4 file=ContactForm.tsx %}

Here, we  import several items from the 'react' and 'react-bootstrap' packages:

We defined the component as a functional component, using the FC type from React. The function is named ContactForm.

We are using the `useState` hook to initialize a piece of state called `contact`, which is an object that contains the values of our form fields. Initially, all of the fields are empty strings.

We then define an event handler function called `handleOnChange` that will be called whenever the user types something into one of the form fields. 

This function uses destructuring to get the name and value properties of the target object, which is the input element that triggered the event. 

It then uses the `setContact` function to update the contact state, by returning a new object that has the same properties as the previous contact object, but with the name property set to the new value.

We defined another event handler function called `handleOnSubmit` that will be called when the user submits the form. 

This function prevents the default form submission behavior (which would cause a page refresh) and logs the contact object to the console. 
We have not implemented the logic for submitting the form yet.

We returned a `Form` element from the react-bootstrap package. The `onSubmit` prop is set to the `handleOnSubmit` function, so that it will be called when the form is submitted. The form also has a `className` of "contact-form".

The component returns several Form.Group elements from the react-bootstrap package. Each Form.Group represents a form field, with a controlId prop that uniquely identifies it. 

The Form.Control element within each Form.Group represents the actual input field, with props for name, value, type, placeholder, and onChange.

The component also returns a `Button` element from the react-bootstrap package, which is used to submit the form. It has a variant of "primary", a type of "submit", and a className of "submit-btn".

Now, let's add our Header and `ContactForm` component to our `App.tsx `component.  Open the App.tsx file and import these components there. Your `App.tsx` file should now look like this:

{% gist https://gist.github.com/jamesoyanna/b85ce0d7fea468991ff4dfdda13eebe4 file=App.tsx %}

Checking your application on your broswer, it should now look like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yjcdymrykfq7krfxbr7k.PNG)

### Storing submitted contact information:

Now, let's display the added  phone contacts on the page.
To properly manage and store our contacts, we will be using the `useReducer` hook, a built-in hook in React that would enable us to manage state using a reducer function. 

### Adding types to our application:
In your `src` folder, create a file, name it `types.ts` and add the following content to it:

{% gist https://gist.github.com/jamesoyanna/3befdca6940a9cef79809bf247c1473c file=types.ts %}

Here, we have two interfaces- Contact and Action interface.

The `Contact` interface defines the shape of an object that represents a contact.

The Action interface defines the shape of an object that represents an action.

Create a new folder inside your `src` folder and name it `reducers`. Create a file inside the reducers folder and name it `contactsReducer.ts` and add the following content into it:

{% gist https://gist.github.com/jamesoyanna/e222c333227932cbf24911fbe09f5d4d file=contactsReducer.ts %}

Here, we firstly import the `Contact` and `Action` interfaces from the `types.ts` file 

We then define an interface called `AppState` which has a single property, contacts, which is an array of Contact objects. This represents the state of the application that this reducer manages.

We define and export the function `contactsReducer` which takes two arguments: state and action. 

The state argument represents the current state of the application, while the action argument represents an action that has been dispatched to update the state. 

The return value of this function is the new state of the application.

We use a switch statement to check the type property of the action argument to determine what action is being performed. 

In this case, the type property is expected to be a string that matches the value "ADD_CONTACT", which will be defined later.

 We returned a new object that represents the new state of the application. 

It copies all the properties of the previous state using the spread operator ...state, and then updates the contacts property with a new array that includes all the previous contacts (...state.contacts) plus the new contact that was passed in the action.payload property.

`default: return state;`: This default case returns the current state unchanged if the action type is not recognized.


In order to use the `contactsReducer`, let's import it into App.tsx.
Now, open the App.tsx file and update the code inside to this one below:
{% gist https://gist.github.com/jamesoyanna/e70db1b4a665379760288f680942fc5e file=App.tsx %}

`const initialState: AppState = { contacts: [] }; `. In this line we define the initial state for the` contactsReducer`. 

`const [state, dispatch] = useReducer(contactsReducer, initialState); ` 

In this line of code we use the `useReducer` hook from React to create a state management system for the App component.

` useReducer` takes two arguments: the first argument is a reducer function, and the second argument is the initial state. 

In this case, the `contactsReducer` function is used as the reducer, and the `initialState` object is passed as the initial state. 

`useReducer` returns an array with two elements: the current state (state) and a dispatch function that can be used to dispatch actions to update the state. 

The state variable is used to store the current state of the component, while dispatch is a function that can be used to update the state by dispatching actions to the `contactsReducer` function.

`  <ContactForm dispatch={dispatch} />`
Here, We pass the dispatch function as a prop to the `ContactForm `component so we can dispatch the action to add a contact to the contacts array.

You will get a Typescript error highlighted at `dispatch`. This is because when we pass any prop to the ContactForm  component, we need to state the type of the `dispatch` prop in the component props list.

In order to specify the dispatch prop type, you can declare an interface named `ContactFormProps` above the component declaration in the `ContactForm.tsx` file. 

Add this code to your ContactForm.tsx file 

```
interface ContactFormProps {
  dispatch: React.Dispatch<Action>;
}
```

We use it inside the angle brackets after : FC.

Now, we use the dispatch prop like this:

`const ContactForm: FC<ContactFormProps> = (props) => {
  const { dispatch } = props;
  // ....
};`

Also ensure you add an import for the Action type at the top of the file like this:

`import { Action } from '../types';`

Your updated code in the `ContactForm.tsx` file should now look like this:

{% gist https://gist.github.com/jamesoyanna/f2380e7926534b240ad14c001f4e34ee file=ContactForm.tsx %}

So what we do in the code is to indicate that the `ContactForm `component will receive a prop with the name `dispatch` whose type is React.Dispatch<Action>.

### Implementing the logic to submit our form:

inside the `handleOnSubmit` method in `ContactForm.tsx` file, add the following code: 

```

 dispatch({
      type: 'ADD_CONTACT',
      payload: contact
    })
```
Here, we dispatch an action to the Redux store using the dispatch() function. 
The action is an object with a type property set to the string 'ADD_CONTACT' and a payload property set to the variable contact.

Your `ContactForm.tsx` file will look like this:

   {% gist https://gist.github.com/jamesoyanna/0162b28f2354abdb23a1a2e19efedf4e file=ContactForm.tsx %}

### Adding the contact List Page:
Now, we want to display all the contacts we will be adding using the form.
Let's create a Page to handle that.
Inside your components folder, create a file, call it `ContactList.tsx` and add the following content.
  
   {% gist https://gist.github.com/jamesoyanna/3b9735f992ed78ed99909301996e539e file=ContactList.tsx %}

Here, the `ContactList` component takes in an object with a contacts property of type Contact[] (an array of Contact objects) as its props. The component then renders a table that displays the contacts in the contacts prop.

The component returns a JSX that renders the contacts array as a table. It maps over the array and renders a table row for each Contact object, displaying their firstName, lastName, phoneNumber and address properties in separate columns.

We can now display the `ContactList` component in the `App.tsx` file. 

Import the `ContactList.tsx` file into the App.tsx file and add it below the ContactForm component.

Your App.tsx file should now look like this:

   {% gist https://gist.github.com/jamesoyanna/7b07acb91995c8ba4f3d635948583fac file=App.tsx %}

Here, we added a conditional statement that renders the `ContactList` component if the contacts array in the state has any items in it. If the array is empty, the `ContactList `component will not be rendered.

If you check your browser console, you will see a warning in the console as shown below:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0l3vflgrxtkr9bklt2oq.PNG)

This warning message is indicating that each child element of the list returned by the map function in `ContactList `should have a unique "key" prop.

In React, when rendering a list of elements, it's important to provide a unique key for each item in the list. 

This allows React to efficiently update and re-render only the elements that have changed, instead of re-rendering the entire list every time the state changes.

Let's fix this. 

In the `ContactForm.tsx` file, change the below code:

```
dispatch({
  type: 'ADD_CONTACT',
  payload: contact
});
```

```
to this one:
dispatch({
  type: 'ADD_CONTACT',
  payload: {
    id: Date.now(), // returns current timestamp
    ...contact
  }
});
```
Here, we have added extra `id` property to the payload

Upon adding it, Typescript error will be underlined on it. Let's fix it.

Open the types.ts file and add id to the Contact interface like this:

```

export interface Contact {
  id: number;
    firstName: string;
    lastName: string;
    phoneNumber: string;
    address: string;
    email: string;
  }
```

Now open the ContactList.tsx file and add the id as key prop to the child `tr `elements that are returned by the map function like this:

```
{contacts.map(({ id, firstName, lastName, phoneNumber, address, email }) => (
  <tr key={id}>
    <td>{firstName}</td>
    <td>{lastName}</td>
    <td>{phoneNumber}</td>
    <td>{address}</td>
    <td>{email}</td>
  </tr>
))}
```

Let's do a bit of refactoring to our code. 

We will separate the component for displaying different information so it’s easy to re-use and test that component when required.


Create a `ContactItem.tsx` file inside the components folder and move the contents from the map method of the ContactList.tsx file inside it.

Your `ContactItem.tsx` file will look like this:

   {% gist https://gist.github.com/jamesoyanna/a5951f181b2d4904f0a942aef50c0efd file=ContactItem.tsx %}

Then change the map method of the `ContactList.tsx` file from the below code:

```
{
  contacts.map(({ id, firstName, lastName, phoneNumber, email, address }) => (
    <tr key={id}>
      <td>{firstName}</td>
      <td>{lastName}</td>
      <td>{phoneNumber}</td>
      <td>{email}</td>
      <td>{address}</td>
    </tr>
  ));
}
```

To this:

```
 {contacts.map(({ firstName, lastName, phoneNumber, address, email, id}) => (
              <ContactItem
              key={id}
              id={id}
              firstName={firstName}
              lastName={lastName}
              phoneNumber={phoneNumber}
              email={email}
              address={address}
              />
            ))}
```
Do ensure you import the `ContactItem` into the `ContactList.tsx` like this:
`import ContactItem from './ContactItem';`

Now let's add the ability to **Edit** and **Delete** a phone contact.

We will add the Edit and Delete icons using the `react-icons` library.

We have installed the library when we were starting the project.

In the `ContactList.tsx` file, let's add two additional items for editing and deleting in the table heading like this.

```
 <thead className='contacts-list-header'>
            <tr>
              <th>First Name</th>
              <th>Last Name</th>
              <th>Phone</th>
              <th>Email Address</th>
              <th>Adress</th>
              <th>Edit</th>
              <th>Delete</th>
            </tr>
          </thead>
```

Now, open the `ContactItem.tsx` file and replace it with this contents:
 {% gist https://gist.github.com/jamesoyanna/eea0e4aed5f67a2fa97f95d29facaa21 file=ContactItem.tsx %}

Here, we added this - `import { AiFillDelete, AiFillEdit } from 'react-icons/ai';` to import the Edit and Delete icons from the react-icon library.

```

     <td>
        <AiFillEdit size={20} color='blue' className='icon' />
      </td>
      <td>
        <AiFillDelete size={20} color='red' className='icon' />
      </td>
```
We added this code to make use of our icons in the table data.

Your application should now look like this on your browser:


![Phone-contact app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d26ds5v0v9as6k7mon0e.PNG)

We will now implement the functionality for editing a contact.

In order to show the edit modal popup, we will make use of the react-bootstrap modal component.

Inside your component folder, create a file and name it `EditModal.tsx`. 
Add the this content below inside the file.

   {% gist https://gist.github.com/jamesoyanna/107e4ca7ffd4cce8a7556e8ba7249c38 file=EditModal.tsx %}

Here, we define a EditModal functional component. The component accepts `toggleModal, dataToEdit, showModal, dispatch` props.

– `toggleModal `which is a function that will toggle the state value used to hide or show the modal

– `dataToEdit `will be an object containing contact details of the contact to be edited

– `showModal `will be a boolean value indicating whether to show or hide the modal

– `dispatch `function which will be helpful to dispatch the edit contact action 


The component uses the Modal component from the `react-bootstrap` package to render a modal dialog that displays a form for editing contact information. The `ContactForm `component is used to render the form.

We also define the `EditModalProps `interface, which describes the shape of the props object that the component receives.

Right now, our `ContactForm `component accepts only the dispatch prop so let’s add the remaining required prop in the definition of the type.

Open the `ContactForm.tsx` file and change the interface to the below code:

```
interface ContactFormProps {
  dispatch: React.Dispatch<Action>;
  dataToEdit: Contact | undefined;
  toggleModal: () => void;
}
```

Don't forget to add an import for the Contact and Action at the top of the file like this:

`import { Action, Contact } from '../types';`  

Now, update state object in the `ContactForm `component to the content below:

```
const ContactForm: FC<ContactFormProps> = ({  dispatch, dataToEdit, toggleModal}) => {
  const [contact, setContact] = useState({
    firstName: dataToEdit?.firstName ? dataToEdit.firstName : '',
    lastName:  dataToEdit?.lastName ? dataToEdit.lastName : '',
    phoneNumber: dataToEdit?.phoneNumber ? dataToEdit.phoneNumber : '',
    address: dataToEdit?.address ? dataToEdit.address : '',
    email:   dataToEdit?.email ? dataToEdit.email : '',
  });
```

Here we created a state object for the contact form, and populating its initial values based on any data that might be passed to the component for editing. 

If any of the fields are edited by the user, the 'setContact' function can be used to update the state and re-render the component with the new values.

Update the `handleOnSubmit `method to the below code:

```
const handleOnSubmit: FormEventHandler<HTMLFormElement> = (e) => {
    e.preventDefault();
    if(!dataToEdit){
      dispatch({
        type: 'ADD_CONTACT',
        payload:{
          id: Date.now(),
          ...contact,
        }
        
      })
    } else {
      toggleModal();
    }
  };
```
So at application startup, the 'dataToEdit' variable will be undefined if the user has not clicked on the edit icon. If the edit icon has been clicked, 'dataToEdit' will contain the contact details to be edited.

To handle this, we check if we are currently editing a contact. If we are not, we dispatch the 'ADD_CONTACT' action to add the new contact. If we are editing a contact, we simply close the modal without taking any further action at the moment.

Once we have dispatched the 'ADD_CONTACT' action, we are calling the `toggleModal` function to close the modal.

 Modify the code for the 'Add Contact' button as follows:

```
<Button variant='primary' type='submit' className='submit-btn'>
  Add Contact
</Button>
```
to this code:

```
<Button variant='primary' type='submit' className='submit-btn'>
  {dataToEdit ? 'Update Contact' : 'Add Contact'}
</Button>
```
By default, the contact form will display the 'Add Contact' button text. If the user clicks on the edit icon, the 'dataToEdit' prop value will be set, and the modal will display the 'Update Contact' text while the user edits the contact information.

Now replace the current content of the `App.tsx` file with the following code:

   {% gist https://gist.github.com/jamesoyanna/81cc56e3fa22b46a28ad0321ce64a65f file=App.tsx %}

Here, two additional states have been declared in the code above.

The code includes two `useState `functions. The first one controls whether the modal is visible or hidden, while the second one stores the details of the edited contact as an object.

Initially, the object is undefined, but once a value is set, it is of the Contact type with properties such as id, `firstName`, `lastName`, and `phoneNumber`. 

To avoid any future TypeScript errors while using `dataToEdit `or setDataToEdit, the type is declared in angle brackets.

In the useEffect hook, the dataToEdit value is set back to undefined once the modal is closed, i.e., when the `showModal `value is false.

In the `toggleModal `function, the updater syntax of state is used to change the showModal state from true to false and vice versa. 

If the modal is already open because the `showModal `value is true, calling the `toggleModal `function will close the modal. On the other hand, if the modal is already closed, calling the `toggleModal `function will display the modal.


As you would observed in the `App.tsx` file, `dispatch` and `handleEdit` are passed as props to the `ContactList` component. Therefore, we need to accept them in the `ContactList` component.

To do this, open the `ContactList.tsx` file and replace its contents with the following code:

 {% gist https://gist.github.com/jamesoyanna/b3ae24bc7e331fa52d8154d38666596a file=ContactList.tsx %}

We can observe here that, `handleEdit` function takes id as a parameter and does not return anything. Therefore, it has been defined in the `ContactListProps` interface as follows:

```
interface ContactListProps {
  // ...
  handleEdit: (id: number) => void;
  // ...
}
```
Next, we extract the `handleEdit` and dispatch as props and pass them to the `ContactItem` component as illustrated below:

```
 <ContactItem
  key={contact.id}
  {...contact}
  handleEdit={handleEdit}
  dispatch={dispatch}
  />
```
Now, open the `ContactItem.tsx` file and replace it with the following content:
 {% gist https://gist.github.com/jamesoyanna/d4e42009b262580d60f0e286adf1f7f9 file=ContactItem.tsx %}

Earlier, the ContactItem component was solely receiving attributes from the Contact interface.

we are now also providing the `handleEdit` and dispatch props, and thus, we have defined another interface as follows:

```
interface ExtraProps {
  handleEdit: (id: number) => void;
  dispatch: React.Dispatch<Action>;
}
```

Upon reviewing the application, it can be observed that the modal displays the contact information of the selected contact being edited, as depicted below:

![Application displaying modal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7n4lo7ax9tvyqfuf0r25.PNG)

### Implementing Edit functionality:

We currently have the user interface to edit and delete. Our next step is to include the code that will enable these functionalities. 

To achieve this, you should access the `contactsReducer.ts` file and append a switch case for the `UPDATE_CONTACT` action. 
Your contactsReducer.ts file should now look like this:

 {% gist https://gist.github.com/jamesoyanna/45d309b118606045a39ec76907d059d1 file=contactsReducer.ts %}

Here, The id of the contact and the updates object containing the new data are being sent for updating, as evident from the above. 

The contact with the matching id is being updated using the array map method. 
However, upon saving the file, a TypeScript error occurs with this case.

![Upadate error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cim6k8zbqwprrwt9zpyy.PNG)

The reason for the error is that the Action interface specifies the payload as a Contact object with properties including id, firstName, lastName,, address and phoneNumber.

However, when handling the UPDATE_CONTACT case, we are only interested in the id and updates properties.

To resolve the error, we must inform TypeScript that the payload can be either a Contact object or a type that includes id and updates properties.

Now, in your types.ts file, let's add a new interface as shown below:

```

export interface Update {
  id: number;
  updates: Contact;
}
```
Then update the Action interface to this:

` export interface Action {
    type: 'ADD_CONTACT' | 'UPDATE_CONTACT'
    payload: Contact | Update;
  }`

After this modification, payload is now a union type that can be either of Contact type or Update type, and type is a string literal type that can be either `'ADD_CONTACT'` or `'UPDATE_CONTACT'`.

Your types.ts file should now look like this:
{% gist https://gist.github.com/jamesoyanna/e3ce0ac1b43f46783e73af2f2a4fe815 file=types.ts %}

Next, import the new action interface into the contactsReducer.ts file

However, you may encounter additional TypeScript errors in your `contactsReducer.ts` once you make these changes. Lets see how to fix them.

```
So change ADD_CONTACT switch case from the below code:

case 'ADD_CONTACT':
  return {
    ...state,
    contacts: [...state.contacts, action.payload]
  };
```
to this code:
```js
case 'ADD_CONTACT':
  return {
    ...state,
    contacts: [...state.contacts, action.payload as Contact]
  };
```
In this code above, we are using the as keyword for type casting, which explicitly informs TypeScript about the type of action.payload.

And now change the UPDATE_CONTACT switch case from the below code:

```
case 'UPDATE_CONTACT':
  const { id, updates } = action.payload;
    return {
      ...state,
      contacts: state.contacts.map((contact) => {
        if (contact.id === id) {
          return {
            ...contact,
            ...updates
          };
        }
        return contact;
      })
    };
```
To this one:

```
case 'UPDATE_CONTACT':
  const { id, updates } = action.payload as Update;
    return {
      ...state,
      contacts: state.contacts.map((contact) => {
        if (contact.id === id) {
          return {
            ...contact,
            ...updates
          };
        }
        return contact;
      })
    };
```

By specifying the type of action.payload as Update for the UPDATE_CONTACT case, we have resolved the TypeScript errors.

With this modification, the updated `contactsReducer.ts` file will now look like this:

{% gist https://gist.github.com/jamesoyanna/aabb924c4f438b1116fd6e1c7cd29b70 file=contactsReducer.ts %}

To update the contact, you need to dispatch the UPDATE_CONTACT action. You can do this by adding the following code inside the `handleOnSubmit` method of the `ContactForm.tsx` file, before calling the `toggleModal` function:

Open the `ContactForm.tsx` file and inside the `handleOnSubmit` method, in the else block, before the `toggleModal` function call, add the below code:

```
dispatch({
  type: 'UPDATE_CONTACT',
  payload: {
    id: dataToEdit.id,
    updates: {
      id: Date.now(),
      ...contact
    }
  }
});
```
`And inside the if condition after the dispatch call, add the below code:`

```
setContact({
  firstName: '',
  lastName: '',
  phoneNumber: '',
  address: '',
  email: ''
});
```
In this code, we are resetting the form state. This ensures that when we dispatch the ADD_CONTACT action, all the user-entered data is cleared out.

Now, if you check the application, you will notice that the contact can be edited successfully.

Upon adding the code in your handleSubmit, your final `ContactForm.tsx` file should now look like this:

{% gist https://gist.github.com/jamesoyanna/652194ba189840de354ee4af7f05e73e file=ContactForm.tsx %}

### Implementing Delete Contact Functionality:
Let us proceed with the addition of the delete contact feature by opening the `contactsReducer.ts` file and including a switch case for the DELETE_CONTACT action.

```

case 'DELETE_CONTACT': {
    const { id } = action.payload;
    return {
      ...state,
      contacts: state.contacts.filter((contact) => contact.id !== id)
    };
  }
```

To remove a contact, we include only its id in the payload property and apply the array filter method to eliminate the corresponding contact

Now, in the types.ts file, change the Action interface to the following code:

```
export interface Action {
  type: 'ADD_CONTACT' | 'UPDATE_CONTACT' | 'DELETE_CONTACT'
  payload: Contact | Update;
}
```
Here, we have included DELETE_CONTACT as an additional type.

Open the `ContactItem.tsx` file and, within the Delete icon, add an onClick attribute, an event handler that would be triggered when a user clicks on the delete button.

```
   <AiFillDelete size={20}     onClick={() => {
            const confirmDelete = window.confirm(
              `Are you sure you want to delete contact for user ${firstName} ${lastName}?`
            );
            if (confirmDelete) {
              // dispatch action
            }
          }} color='red' className='icon' />
```
Here have added a function to display a confirmation dialog box asking the user if they want to delete the contact for the user whose first name and last name are stored in the `firstName` and `lastName` variables.

If the user confirms the delete action, the dispatch function is called to send an action to the store. 

Your `ContactItem.tsx` file should now look like this:
{% gist https://gist.github.com/jamesoyanna/463c09b524ad816f1a982e9751865a43 file=ContactItem.tsx%}

However, upon saving the file, a TypeScript error will appear, which is demonstrated below:

![Delete Error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihw7su6y9kdgz6c2bch2.PNG)

The reason for the error is that the Action interface in the `contactsReducer.ts` file specifies that the payload can be either a Contact or Update, but for the DELETE_CONTACT action, we're only passing an object with an ID inside it and we're missing the 'updates' property.

To resolve this issue, you'll need to modify the Update interface in the following code:


`export interface Update {
  id: number;
  updates: Contact;
}
`
to this code:
`
export interface Update {
  id: number;
  updates?: Contact;
}`

In this instance, we've added a question mark symbol to the 'updates' property to make it optional. This resolves the TypeScript error, as we're providing the 'id' property and the 'updates' property can be disregarded.

By making this adjustment, the error in the `ContactItem.tsx` file will disappear.

If you check the application now, you'll notice that the delete contact feature is functioning correctly

### Implementing Validations in our form
At this point, the application's CRUD (Create, Read, Update, and Delete) functionality is complete.

However, we still need to implement validation for adding or modifying contacts.

To achieve this, begin by creating a new state within the `ContactForm.tsx` file:

const [errorMsg, setErrorMsg] = useState('');

Here, we declare a state handle error messages

Modify the handleOnSubmit method in the `ContactForm.tsx` file to the following code:


```
  const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const {firstName, lastName, phoneNumber, address, email} = contact;
    if (
      firstName.trim() === '' ||
      lastName.trim() === '' ||
      phoneNumber.trim() === ''||
      address.trim() === ''||
      email.trim() === ''
    ) {
      setErrorMessage('All the fields are required.');
      return;
     } else if (phoneNumber.length < 3) {
      setErrorMessage('Please enter a phone number with more than 3 numbers.');
      return;
    }
    if (!dataToEdit) {
      dispatch({
        type: 'ADD_CONTACT',
        payload: {
          id: Date.now(),
          ...contact
        }
      });
      setContact({
        firstName: '',
        lastName: '',
        phoneNumber: '',
        address: '',
        email: '',
      });
      setErrorMessage('');
    } else {
      dispatch({
        type: 'UPDATE_CONTACT',
        payload: {
          id: dataToEdit.id,
          updates: {
            id: Date.now(),
            ...contact
          }
        }
      });
      toggleModal();
    }
  };
```

In this `handleSubmit` function, extracts the firstName, lastName, and phoneNumber, address, email properties from the contact state.

 We then checks if these properties are empty or contain only whitespace, and if so, we set an error message with setErrorMessage and return from it.

If the phone number is not up to 3 numbers, it sets a different error message and returns from the function.

Now, we will display the error message on the screen. To do this, add the following code inside the Form tag and before the Form.Group tag while returning the JSX:

`{errorMsg && <p className='errorMsg'>{errorMsg}</p>}`

Your entire ContactForm.tsx files hould now look like this:

{% gist https://gist.github.com/jamesoyanna/d7617b65f4bb97aaeebd6f030dd67bcb file=ContactForm.tsx%}

With these modifications, we have successfully completed building our Phone Book application using React + TypeScript.

The source-code for this project can be found [here](https://github.com/jamesoyanna/phone-book-app)