Learning TypeScript with React - Part 1

analizapandac

Ana Liza Pandac

Posted on July 1, 2019

Learning TypeScript with React - Part 1

⚡TL;DR: Understanding what are types, type annotations, why use them and how to use them can help you catch errors during development while also enhancing code quality and readability.

Two weeks ago, I decided to pick up TypeScript so I started learning it by creating TEDFlix. Built together with React, it fetches the videos from the official Tedx Talks Youtube channel for you to watch. Why TEDFlix? It sounds fun and honestly, I ran out of ideas 😛

In this two-part series, I wanted to share what I learned from doing this project.

Before diving into it, let me give you a short definition of what is TypeScript (TS) taken from the official TS website.

“TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.”

Now, let me also give you a high level overview of the app’s features and how the React side is structured.

It is a one page app where it has a video player, a list of related talks and a search bar which are all built as separate React components. On page load, it fetches a default list of talks from a JSON file instead of fetching from Youtube to avoid exceeding the daily usage quota of the Youtube API when the page is loaded by many users. The app only communicates with Youtube when searching for talks.

Okay, let's start.

First, the project setup

I generated the project using Create React App with TypeScript

create-react-app my-app-name --typescript
Enter fullscreen mode Exit fullscreen mode

How did I use TypeScript in this app?

Since I’m a TS beginner, I get started by learning the syntax and features of the language first specifically the types, type annotations and interfaces. In this first post, I'm gonna be talking about types and annotations only.

What is a type?

Since TypeScript is a typed language, it means we can specify/annotate the type of the variables, function parameters and object properties.

From my own understanding, a type is a symbol/representation of all the properties and methods that a variable has access to. It means if we added a type of number to a variable, the TS compiler knows that the variable has and can only access all the properties and methods that a number has.

A type is annotated to the variable, parameter or property using this format :type.
For example, let name: string.

There are a lot of available types in TS however, in this app, these are the ones that I've used:

  1. Primitive Types - number, string, boolean
  2. Arrays - by adding [] after the type (e.g. let names: string[])
  3. Video - an interface or a custom type I created to represent a video object's properties

See here for a more comprehensive list of types.

Why do we care about annotating types?

  1. Types are one of the best forms of documentation you can have. This is a very helpful to the next developer who has to read your code which could also be the future you.
  2. It helps the TypeScript compiler help you. If you annotate a variable as a number and a few lines later assigned it a value which is a string, the compiler will give you the following error.
let x: number = 123;
x = '123'; // Error: cannot assign a `string` to a `number`
Enter fullscreen mode Exit fullscreen mode

Even if we remove the :number annotation from variable x, the same error will be given by the compiler because TypeScript is smart*.

*If you declare a variable with a value without specifying the type, TypeScript will figure out the type of the variable based on the initial value assigned to it.

This is called type inference.

"So if type inference is present then why do I have to bother annotating the variables?"

Type inference does not work all the time.

An example scenario is when you delay the initialization of a variable as shown below.

let age;

// a few lines later
age = 12; 
// The compiler will NOT give an error even 
// if we assign a non-numeric value to `age`
age = 'Ana'; 
Enter fullscreen mode Exit fullscreen mode

If you delay the variable initialization without annotating a type to it, the variable will automatically have a type of any associated with it since the TS compiler does not have any idea what kind of properties age will have later on.

Variables with a type of any should be avoided as much as possible. It defeats the purpose of the idea behind the TS type system where we want to catch as many errors as possible during development. Why? Because, the compiler cannot do error checking on types of any.

Remember, use types to help the TS compiler help you.

How is type annotation used in the app?

Aside from using types on the variable declarations, I also used annotations in the function declarations.

A function can be annotated in the following ways:

1. Arrow function

const add = (a:number, b:number):number => {
 return a + b;
}

// or
const add: (a: number, b: number) => number = (a, b) => {
  return a + b;
};
Enter fullscreen mode Exit fullscreen mode

2. Non-arrow function

function add(a:number, b:number):number {
 return a + b;
}
Enter fullscreen mode Exit fullscreen mode

In both of these examples, the compiler will give an error if the function returns a string or any type that is not a number since it is expecting a number.

For fetching the channel's videos, I created a function called fetchChannelVideos which accepts a boolean flag indicating whether to fetch the default videos from the JSON file and a search query string. Both of these are optional parameters (by adding ? after the property name) which are represented as an interface. I will explain later what an interface is but for now let’s take a closer look on how the function is annotated.

interface FetchVideosArguments {
 shouldUseDefaultVideos?: boolean;
 searchQuery?: string;
}

export const fetchChannelVideos: (
 args: FetchVideosArguments
) => Promise < Video[] > = async ({
 shouldUseDefaultVideos = false,
 searchQuery
}) => {};
Enter fullscreen mode Exit fullscreen mode

On the left side of the assignment operator (=),

const fetchChannelVideos: (args: FetchVideosArguments) => Promise <Video[]>
Enter fullscreen mode Exit fullscreen mode

we are annotating the variable fetchChannelVideos that was declared not the function assigned. We are telling the TS compiler that this variable will have a function assigned to it with these types of arguments and return value.

While the right part of the = is the function assigned.

async ({
 shouldUseDefaultVideos = false,
 searchQuery
}) => {};
Enter fullscreen mode Exit fullscreen mode

To annotate the function itself, we have to specify its arguments and their types and the return value as well.

So why didn't I annotate the function to assigned to fetchChannelVideos? Because again, TypeScript is smart.

Seeing that I assigned the function to a variable that was annotated, it is able to infer that the function will have the same argument names and types and the return value as well, otherwise it will give an error if I add or specify different argument names or return a different value.

*The function arguments and return value is inferred

However, if I’m exporting the function directly without assigning it to a variable then I have to annotate it like below.

export async function fetchChannelVideos({
 shouldUseDefaultVideos = false,
 searchQuery
}: FetchVideosArguments): Promise<Video[]> {
 // function body
}
Enter fullscreen mode Exit fullscreen mode

Okay, now that we have an idea about the what, why and how of type annotations, there's one last question.

Where do we use types?

The answer is: everywhere. By using TypeScript, every data in your application will have a type associated with it whether you like it or not.

Closing Thoughts

I have only touched the basics so far but I’ve already seen how helpful it is, seeing the errors the compiler gives while writing the code instead of discovering them later when running the app saved me a lot of time.

Learning Resources

If you want to learn more and join me on this journey, here are some available resources that can help you get started.

TypeScript in 5 Minutes

TypeScript Deep Dive

Official TypeScript Documentation


I deployed the app in Netlify: https://tedflix.netlify.com/

I will share the Github repo of the project soon.


*Update: 06/07*
Last part about interfaces is up 🎉


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.

Cheers!

💖 💪 🙅 🚩
analizapandac
Ana Liza Pandac

Posted on July 1, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related