Learning TypeScript with React - Part 2 (The what, why and how of interfaces)
Tags: typescript, react, javascript, webdev
Published: 2019-07-06 13:19:50

---
title: Learning TypeScript with React - Part 2 (The what, why and how of interfaces)
published: true
description: This is the last part of the two-part TypeScript series where we learn what is an interface, why should you care about it, and how to use it to write more reusable code.
tags: typescript, react, javascript, webdev
cover_image: https://thepracticaldev.s3.amazonaws.com/i/0g1hvvmk5ty1x3e24pjw.png
---

:zap:TL;DR: _Understanding what are interfaces, why use them and how to use them can help you in writing more reusable code and creating awesome applications._

In the [previous article](https://dev.to/analizapandac/learning-typescript-with-react-part-1-3ohn), we talked about types, what is it, how to use them and why use them. If you haven't read it yet, I recommend that you read it first.

In this post, we'll get to know what is an interface, why should you care about it, and how to use it to write more reusable code.

Let's begin.


### **What is an interface?**

Interfaces are the core way in TypeScript to compose multiple type annotations into a single named annotation.

It’s a way of creating a new type that describes an object’s property names and their types. Remember the types that we covered before (number, boolean, string, etc.)? **An interface is the same as those types.** 


### **Why should you care about interfaces?**

For me, interfaces are one of the best features of the TypeScript language. Let me show you just how awesome it is.

Let's start with the following example.

You have a function called `renderVideo` which accepts `video` as a parameter in which you annotated with all the properties that should be present in a video object.

```javascript
const video = {
  videoId: '',
  title: '',
  description: '',
  thumbnailURL: ''
};

const renderVideo = (video: { videoId: string; title: string; description: string; thumbnailURL: string }): void => {

}
```
Even though the parameter annotation is quite long, the code above is okay, the function parameter and return value was annotated correctly.

**However**, imagine if you added more functions which accepts a video.
 
```javascript
const video = {
  videoId: '',
  title: '',
  description: '',
  thumbnailURL: ''
};

const renderVideo = (video: { videoId: string; title: string; description: string; thumbnailURL: string }): void => {

}

const getVideoSummary = (video: { videoId: string; title: string; description: string; thumbnailURL: string }): void => {

}

// another function has a `video` parameter
// another one
// and another one
// *shouts* "DJ Khaled"
```
Aaahhhh. I don't know about you but to me, the code above doesn't look good.

**There are a lot of long annotations which are duplicated several times. The code is harder to read as well.**

Now imagine again (we're imagining a lot here) that you need to do either one or more of the following changes to a video:

- add the date it was published as a new property
- rename `thumbnailURL` to `imageURL`
- change the type of `videoId` from `string` to a number

**Applying these new changes to the code above means you need to change all the video annotations in a lot of places.**

That's a lot of work and we don't want that so how can we solve this? 

**Simple, by using an interface.**


### **How to create an interface?**

We can convert this long video annotation into an interface called `Video`.

> _To create an interface, use the **`interface`** keyword followed by a name that represents the object, in this case **`Video`**._

> The _name should start with a capital letter_ just like how we create React components and a set of curly braces where you declare all of the object's properties and methods and its types.

This is how you create the `Video` interface.

```javascript
interface Video {
  videoId: string;
  title: string;
  description: string;
  thumbnailURL: string;
}
```

### **How do you use an interface?**

Since an interface is a custom type, we can annotate it to a variable just like a normal type.

```javascript
let item: Video;
```

By using the `Video` interface, we can rewrite the previous example to this:

```javascript
interface Video {
  videoId: string;
  title: string;
  description: string;
  thumbnailURL: string;
}

const renderVideo = (video: Video): void => {};
const getVideoSummary = (video: Video): void => {};

// another function that uses a video
// another one
// and another one

const video = {
  videoId: "",
  title: "",
  description: "",
  thumbnailURL: ""
};

renderVideo(video);
```

This code looks wayyyyy better than the previous one right?

It looks cleaner and in one glance, we can see right away that the parameter is a type of `Video`. 

**Most of all, we can add, remove or rename a property or change a property type only in one place, the interface declaration. Awesome!**

> :bulb: If you use VS code, which I highly recommend you should, you can see all the property names and types of an interface by holding the `ctrl/cmd` key and hovering over the interface name.
> ![](https://thepracticaldev.s3.amazonaws.com/i/rm64kjn21s83qhptjvdm.gif)
> Pretty cool right?

### **How are interfaces used in the app?**

Aside from using the `Video` interface, I created another interface to represent how the Youtube API response is structured.

```javascript
interface YoutubeVideo {
  id: { videoId: string };
  snippet: {
    publishedAt: string;
    title: string;
    description: string;
    thumbnails: { medium: { url: string }; default: { url: string } };
    channelTitle: string;
    channelId: string;
  };
}

interface YoutubeAPIResponse {
  data: { items: YoutubeVideo[] };
}
```

This interface is used in the `fetchChannelVideos` function.

```javascript
export const fetchChannelVideos: (
  args: FetchVideosArguments
) => Promise<Video[]> = async ({
  shouldUseDefaultVideos = false,
  searchQuery
}) => {
 const requestURL = '';
 const response:YoutubeAPIResponse = await axios.get(requestURL);
};
```

**Since an interface is a type, it means the TS compiler also does error-checking on the annotated data.**

By creating an interface for the API response structure and annotating it to the variable, we made sure that we don't accidentally access a property that does not exist.

So if we try to access `comments`, which is not included in the API response, the TypeScript compiler will give us an error.

### **Writing Reusable Code with Interfaces**

Now that we covered the what, why and how of interfaces, let's talk about how we can use it to write more reusable code. 

Let's say you have a component that renders comments from a Youtube user and the channel.

First we write it like this:

```javascript
interface User { name: string; avatar: string; }
interface Channel { name: string; avatar: string; }

const renderUserComment: (user: User, comment: string) => React.ReactNode = (
  user,
  comment
) => { /* return user comment */ };

const user = { name: "Ana", avatar: "ana.png" };
const channel = { name: "Tedx Talks", avatar: "tedxtalks.png" };

const renderChannelComment: (
  channel: Channel,
  comment: string
) => React.ReactNode = (channel, comment) => {/* return channel comment */};

renderUserComment(user, 'hello there');
renderChannelComment(channel, 'hi, thanks for watching');
```
There are two separate interfaces to represent a user and a channel as well as separate functions to render these comments even though they do the same thing, rendering a comment with the author.

#### **How can we rewrite this to remove the duplicated code?**

Although we can use a [union type](https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types) to indicate that the comment author can be a `User` or a `Channel`,

```javascript
const renderComment: (author: User|Channel, comment: string) => React.ReactNode = (
  author,
  comment
) => { /* return comment */ };
``` 

**In this scenario, it's better to create one interface to represent the two types of users.**

Let's rewrite it using a more generic interface called `Author`. 

```javascript
interface Author { name: string; avatar: string; }

const renderComment: (author: Author, comment: string) => React.ReactNode = (
  author,
  comment
) => { /* return comment */};

const user = { name: "Ana", avatar: "ana.png", github: "analizapandac" };
const channel = { name: "Tedx Talks", avatar: "tedxtalks.png", channelId: "UCsT0YIqwnpJCM-mx7-gSA4Q" };

renderComment(user, 'hello there');
renderComment(channel, 'hi, thanks for watching');
```

Even though `user` and `channel` represents two different types of data, **they satisfy the requirements to be considered an `author`** which is a `name` and `avatar` so the `renderComment` function works for both objects.

> The examples above are very basic but the point here is that we can use a generic interface to represent different objects which can work with different functions. This is one way to use interfaces to write more reusable code.

### **Closing Thoughts**

Aside from learning about the what, why and how of interfaces, I hope that I have also shown you a glimpse of the power of interfaces and how you can use it to create amazing applications. 

There's a lot more to interfaces especially on how to use it together with the other TypeScript features such as classes and write even better code.

I'll continue learning the more advanced TS concepts, creating new exciting projects using them and sharing them with you. 

I hope you'll do the same :blush:


### **Project Github Repo**
Here's the source code of the app: [https://github.com/analizapandac/tedflix](https://github.com/analizapandac/tedflix)


You can clone it and play with the source code on your local if you want.

You can see the deployed app at [https://tedflix.netlify.com/](https://tedflix.netlify.com/).

---

Here's the previous article:

{% link https://dev.to/analizapandac/learning-typescript-with-react-part-1-3ohn %}

---

Let me know in the comments below if you have any feedback and suggestions or pointers on where to go next. Thank you in advance.