Quick start with Typescript and React
Tags: react, typescript, tutorial
Published: 2021-06-23 05:09:56

Currently, the `React+Typescript` is considered as one of the most popular bundles for creating client-side applications. This combination has a huge potential and allows to [develop solutions of any complexity](http://maddevs.io/services?utm_source=devto&utm_medium=typescript). In this article, we’ll see why `Typescript` is so hyped, discuss some basic examples of working with components, storages, and API queries, and see the benefits of `Typescript`.

**Table of contents**
* Introduction
* React
* Typescript
* Project creation
* Components
* Store
* API
* Props of Typescript
* Const of Typescript
* Conclusion

##React

I assume that all readers know about `React`. Otherwise, it is pointless to proceed reading the article. To enthusiastic non-reacters please go to read [the doc](https://reactjs.org/docs/getting-started.html) and then come back here.

[![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/97iwxahzwnkpglcqym3n.png)](http://maddevs.io/blog/amazing-template-for-react-application?utm_source=devto&utm_medium=software-development)
 
##Typescript

**TypeScript(TS)** is a typed superset of **JavaScript(JS)** that provides compile-time checking of source code and has a bunch of other nice features to native `JS`. `TS` helps us to fix most bugs and provides us with powerful tools to improve code quality. You can read more about the pros and cons of `TS` in other articles, but we’ll go over them a little bit. 

**The goal here to so understand how** `TS` **works within the** `React`, **and what are the pros and cons of** `TS` **and when we should use it.**

##Project creation
So, we should start with creating a project. To create a simple `React+TS` project, I recommend using the `create-react-app` utility with the template parameter:

`$ npx create-react-app  --template typescript`
After that, you will have a `React` project ready to run, in which `TS` support is already configured, and you can immediately start writing code.

###Components
Let’s introduce a small `Button` component, which contains the following logic:
* Handles clicks
* Saves and displays the number of clicks on the button
This simple component, without using `TS`, will be written like this:
```
import React, { useState } from "react";

const Button = ({ onClick, text }) => {
  const [clickCount, setCount] = useState(0);

  const handleClick = (event) => {
    setCount(clickCount + 1);
    onClick(event);
  };

  return <button onClick={handleClick}>{text}(count: {clickCount})</button>;
};

export default Button;
```
And here we already have several problems:

* If we don’t pass a function to the component in the prop `onClick`, or pass a different type of data there, the component will break at runtime (in the `handleClick` function), which you might not notice during development.
* In the prop `text` we can pass any value, which could lead to unexpected output.
Most of the problems are due to the fact that we don’t know what types of data come to us in props. This problem is partly solved by the `propTypes` library, but it has its own limitations — it can only type the component’s props. `TS` allows you to cover everything with types: `handleClick` function, `onClick` function, additional helpers and utilities, stores, and etc. An example of the same component, but using `TS`:
```
import React, { useState } from "react";

interface IProps {
  onClick: (event: React.SyntheticEvent) => void;
  text: string;
}

const Button: React.FC<IProps> = ({ onClick, text }) => {
  const [clickCount, setCount] = useState(0);

  const handleClick = (event: React.SyntheticEvent) => {
    setCount(clickCount + 1);
    onClick(event);
  };

  return (
    <button onClick={handleClick}>
      {text}(count: {clickCount})
    </button>
  );
};

export default Button;
```
So, let’s look at the changes. First, we have described the interface for the props. The interface for props is always called IProps. This interface describes the types of props our component accepts. In this example, we described that the component accepts the function `onClick: (event: React.SyntheticEvent) => void` and the string field `text: string`.

To connect our interface to a component we use the generic type `React.FC`, which takes our props interface as an argument `React.FC`.

We also type the `handleClick` function by describing that it accepts an event with the type `React.SyntheticEvent` [(documentation)](https://reactjs.org/docs/events.html).

Now when we use the component we’ll get an error every time we don’t pass the required parameters (`onClick`, `text`) and this will prevent us from compiling the project.

TS allows you to avoid simple errors with data types that pass through your application and also allows you to structure and strictly define input and output parameters of your functions (Components, Stores and everything else)

##Redux store
In addition to working with components, we often encounter stores. Basically, most of the projects use `Redux` as a centralized data store. In this section, we will take a look at an example of a small `Redux` store on `TS`.

For example, we have a Reducer, which is responsible for our counter (from the component example) and has some actions (`increment`, `decrement`):
```
// action types
enum CounterActionTypes {
  increment = 'increment',
  decrement = 'decrement'
}

// interfaces & types
interface CounterState {
  value: number
}

type CounterPayload = number

interface BaseAction<ActionTypes, Payload> {
  type: ActionTypes
  payload: Payload
}

type CounterAction = BaseAction<CounterActionTypes, CounterPayload>

// actions
const increment = (payload: number): CounterAction => ({
  type: CounterActionTypes.increment,
  payload
})

const decrement = (payload: number): CounterAction => ({
  type: CounterActionTypes.increment,
  payload
})

// reducer
const initialState: CounterState = {
  value: 0
}

const counterReducer = (
  state: CounterState = initialState, 
  action: CounterAction
): CounterState => {
  switch(action.type) {
    case CounterActionTypes.increment:
      return { ...state, value: state.value + 1 }
    case CounterActionTypes.decrement:
      return { ...state, value: state.value - 1 }
    default:
      return state
  }
}

export default counterReducer
```
> I intentionally did not divide the code into several different  > files, although usually in a real project you keep the code 
> divided by entities: `reducer.ts`, `interfaces.ts`, 
> `actions.ts`,`sagas.ts` (or `epics.ts`).

In the first section, we declare `actionTypes`. The `enum` from `TS` is ideal for this. Enum type — is a data type consisting of a set of named values called elements, members, enumeral, or enumerators of the type. In our case, we use an enum to declare the availability `actionTypes` for this reducer. The declaration of `actionTypes` is usually found in the file `actions.ts`
```
enum CounterActionTypes {  
  increment = 'increment',  
  decrement = 'decrement'
}
```
Then comes the declaration of the types and interfaces we need for the reducer. In this example, I’ve added the `BaseAction` interface, which is not usually located directly in each store, but is a common interface used for all actions and is usually separate(for example, in the file `store/interfaces.ts`). Then comes the declaration of the interface, which describes the state of the reducer. In our case the reducer stores only one field: `value: number`. Also, we declare the `CounterPayload = number` type for payloads of all actions that work with this reducer. Finally, the last type is `CounterAction`, which uses a generic `BaseAction` interface with the necessary parameters. All information about types is usually in the file `interfaces.ts`, but it can also be stored next to entities (`CounterState` in reducer.ts, `CounterPayload` and `CounterAction` in `actions.ts`)
```
interface CounterState {  value: number }

type CounterPayload = number

interface BaseAction<ActionTypes, Payload> {  
  type: ActionTypes  
  payload: Payload
}

type CounterAction = BaseAction<CounterActionTypes, CounterPayload>
```
The next section is a simple declaration of action creators. These are simple functions that return actions. Thanks to the typing (`CounterAction`) we keep all action creators looking the same.
```
const increment = (payload: number): CounterAction => ({  
  type: CounterActionTypes.increment,  
  payload
})

const decrement = (payload: number): CounterAction => ({  
  type: CounterActionTypes.increment,  
  payload
})
```
And, finally, the reducer:
```
const initialState: CounterState = {  
  value: 0 
}

const counterReducer = (
  state: CounterState = initialState, 
  action: CounterAction
): CounterState => {  
  switch(action.type) {    
    case CounterActionTypes.increment:      
      return { ...state, value: state.value + 1 }    
    case CounterActionTypes.decrement:      
      return { ...state, value: state.value - 1 }    
    default:      
      return state  
}}
```
In the Reducer, we actively use all the types and interfaces declared above. We use the `CounterState` interface to create `initialState`, and we use state: `CounterState = initialState` and `action: CounterAction` as parameters for the reducer. That way, we can’t use something that we didn’t declare in our interfaces. For example, you can’t add a new field to a state without updating the `CounterState` interface; after adding it, you’ll have to refactor the cases where the new field isn’t returned and `TS` will tell you where and what might be broken. Or, for example, you can’t add a new case to the reducer until you add `actionType` to enum `CounterActionTypes`. This allows us to make our code robust and bug-proof and protect developers from primitive bugs when working with code.

###Working with API
It is also desirable to write interfaces to work with the `API`. Usually, it’s very convenient to describe the `response’s` interface. And if your server is written in `NodeJS` using `TS`, then you can once describe interfaces for `reponse’s` and use them both on the server and on the client. It’s very convenient. Small example of working with `API` using `TS`:
```
const api = {
  posts: "https://jsonplaceholder.typicode.com/posts"
};

export async function request<T>(url: string): Promise<T> {
  const response = await fetch(url);
  const body = await response.json();
  return body;
}

interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}

type PostResponse = Array<Post>

export async function getPosts(): Promise<PostResponse> {
  const posts = await request<PostResponse>(api.posts);
  return posts;
}
```

####Pros of TS
In this section, we will consider all the advantages of `TS` for `React` and highlight the main thesis — why and when to use `TS` together with `React`.

1. Reliability. TS allows you to make your application much more robust. You no longer have to worry about calling a function or accessing an object field — typescript will tell you if you made a mistake and won’t let you compile code with an error.
2. Easy refactoring. You almost never have to worry about breaking something while refactoring. TS simply will not allow you to break the code.
3. IDE support. TS allows you to take autocomplete in your editor to the next level and make it similar to autocomplete in more complex languages(C, Java). Autocompletion, auto-imports, error, and problem highlighting on the fly — all this makes Typescript a great tool for development.
4. Patterns. Typescript is a full OOP language that allows you to write OOP-style code. TS implements some useful features, which do not exist and most likely will never exist in native JS. For example, in TS you can use class access modifiers (public, private, protected), decorators, and Dependency Injection. So, if you use TS, you’re getting much closer to popular patterns of modern development than using native JS. Of course, most often these patterns are not applicable to Frontend applications, but some of them are actively used, for example, in Angular. But React also actively uses the advanced features of TS.
5. A Large community. Typescript is a mature technology with a huge community, and if you have a problem, just google it and chances are someone has already solved it.
6. Open-source. 95% of the libraries and third-party modules are written in Typescript and you should have no problem using them.
7. Learning assistance. TS allows you to learn in more than just JS, because it implements many approaches from other languages. If you know and can use Typescript well, it will be much easier for you to learn and use other languages in the future.

If you are developing or planning to develop a large project with long-term support — TS is your go-to choice. Of course, you can also hard-code in TS, but the language itself regularly punishes you for writing bad code. TS will protect you from the primitive bugs and errors and add confidence to your project. But, don’t forget that typescript helps only at the development stage. After compilation, it completely disappears and runtime works in JS with all its advantages and disadvantages. **If you’re looking for code quality and have enough time to learn and implement the technology, Typescript is your choice!**

< If you choose to use Typescript but exclude unit testing from 
< the workflow, this is a very bad pattern. It’s always better to 
< choose tests over Typescript, because Typescript tests your 
< code, but tests check the business logic, which is much more 
< important!

####TS Pros and Cons
But, as we all know, there is no silver bullet and `TS` also has its disadvantages:

1. You will have to write a lot of code. On TS you will have to write a lot more code. The amount of code in TS is usually 1.5–2 times higher than in native JS. Accordingly, the time you will spend on the tasks increases proportionally by 1.5–2 times. This is the price for reliability. You have to describe new types and interfaces over and over again and be able to apply them correctly. You’ll also have to spend some time studying the interfaces of external libraries and third-party modules in order to correctly integrate them into the project.
2. TS is not for beginners. If your project is planned to be developed by beginner developers (Interns, Juniors), TS is probably not for you. It has a rather high entry threshold. In addition to the complexities of JS, developers will also have to learn the intricacies of Typescipt, which is likely to be very difficult for them.
3. You still can write bad code. Yes, this is bad. If something doesn’t work, you can always use //@ts-ignore or any , but by doing this you create problems for yourself in the future. And if your project doesn’t have strict conditional rules described in tsconfig or eslint (for example, don’t use any , cover everything with types), you won’t benefit from TS.
4. You will have to declare types for libraries. Even if you don’t have to do it that often, it is quite hard. Especially when the library is not a simple utility, but a whole set of utilities. Fortunately, these days there are almost no untyped libraries left (thanks to DefinitelyTyped)
5. Transferring a large production project to TS is difficult. We have tools for that, and you can transfer the project gradually, but all the time you’ll be in pole position and won’t be able to take full advantage of TS. And if you’re also developing features at the same time, the move to TS can drag on for quite a long time.

**Finally,** `TS` **is definitely not the right choice for you**:

1. If you don’t want to write in it or you’re having a hard time writing code in it.
2. If your project’s goal is to **release the product as soon as possible** (`MVP`), then `TS` is also not the best choice for you. You can write the basic version using `JS`, and once the product finds the market fit, rewrite everything using `TS`. 
3. If you have a lot of **Junior developers**, you may have a problem with TS and you probably shouldn’t use it. At least, you should definitely start with a small one. 
4. If you already **have a big working project in** `JS` and you’re planning to rewrite it using `TS`, most likely it’s not worth it. You’d be better off improving your current project code and covering it with tests. This is much more important.
5. If you have the opportunity to write a type and not use `any` — do it. `any` contradicts the main principle of TS — reliability, and exists only to transfer large complex projects to `TS` gradually. And even in that case, it’s better to try not to use `any`. If possible, try to never use any ever.

##Conclusion
In conclusion I would like to say that `TS` is a great tool, which is becoming more and more popular every year. And with `React` it allows you to add the very reliability and transparency, which are usually missing in Frontend applications. In large corporations, `TS` has long been a must-have, but gradually it becomes a must in smaller companies, and hence the number of developers who can use `TS` is increasing. Just try learning and using `Typescript` on a project and you’ll realize how cool this tool is. 

Previously published at [maddevs.io/blog](http://maddevs.io/blog/react-typescript?utm_source=devto&utm_medium=typescript)