Wonder what challenges lie ahead when you want to use TypeScript with React and have a large code base to migrate? Find out in this blog, along with handy tips.
The popularity that TypeScript has been gaining over the last few years is insane. The JavaScript community has adopted TypeScript and we now see many projects that are written in TypeScript.
We can say that React is a neutral framework—it does not force you to use JavaScript or TypeScript, but it leaves the choice to you. In the first years of React’s existence, the standard was to use JavaScript to create React applications. Then the React community started to notice all the benefits that TypeScript can bring to a React code base and started to migrate.
The benefits that TypeScript can bring to a project are many. It improves readability, maintainability and code consistency. Especially in large code bases, TypeScript makes it easy to catch potential bugs and errors well before they ship.
The React community has adopted TypeScript and now sees many more projects written in TypeScript compared to a few years ago. The pairing of React and TypeScript makes total sense and makes it easy to build reliable and performant React applications. Using TypeScript with React provides better IntelliSense and code completion for JSX. We can create reusable React components that are type-safe, avoiding unexpected mistakes along the way.
When deciding to migrate to using TypeScript with React, there are a lot of points that we should consider.
When working on a large code base, we can’t start to change files in any way we please. Every large code base has standards and, usually, the whole team is used to those standards. Changing them without discussing them with the team can quickly create friction.
TypeScript brings many benefits, but starting to adopt it in a large code base without discussing with your team can and will make things worse.
To get team buy-in, you should make a pitch for your team to make the switch. You could create a small presentation with the benefits of TypeScript to make it easier for your teammates who are not used to TypeScript to understand why this change would benefit the team.
For those who have some TypeScript experience, migrating to it can be easy, but we should assume that our team doesn’t have this experience. There are various ways of migrating a React code base to TypeScript but for a large code base, we should consider the best way which would be “gradual adoption.”
The first thing we should do is install TypeScript and create a tsconfig.json file. The tsconfig.json file configures the TypeScript compiler and the relevant resources on our application. TypeScript can automatically create this file for you by installing
TypeScript in your project using yarn add typescript
and running tsc --init
.
After creating our tsconfig.json file, we want to allow vanilla JavaScript files on our code base. (This is a point that can make the pitch for migrating to TypeScript even more viable for your team, so make sure this is clear when you’re discussing
it!) We can allow JavaScript by adding the allowJS
, checkJS
and noEmit
configuration flags.
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"jsx": "react",
"noEmit": true,
"allowJs": true,
"checkJs": true,
"strict": true
}
}
After installing and configuring TypeScript, we can start to gradually change our JavaScript files to TypeScript files. The gradual adoption of TypeScript will make the process easier and will encourage the other developers on your team. We can change the extension from .js to .ts or .tsx on our files and start to see what the warnings that we currently have.
Once the tsconfig.json file is created, VS Code will automatically detect that TypeScript is used and will type check our code. For getting a list of warnings, we can run tsc
on our terminal and the TypeScript compiler will return a list
of type warnings and a non-zero exit code if any issues exist.
After installing, configuring and migrating the JavaScript files to TypeScript, the challenges start to show. Large code bases have many files, and gradually adopting TypeScript means that we should go through every file and fix all the warnings there.
Most of the challenges that a large code base will face when adopting TypeScript are due to interoperability issues between TypeScript and React. Let’s see a few challenges that your team might be facing and how you can solve them.
The defaultProps
static property is an object that we left outside of our component and we define which properties our component should have.
import React from "react";
const User = ({ user }) => {
return (
<div>
<h1>{user.name}</h1>
<h2>{user.age}</h2>
</div>
);
};
User.defaultProps = {
user: {
name: "Leonardo",
age: 21
}
};
export default User;
We don’t need to use defaultProps
when we’re using TypeScript with React. We can define the props for our component using a TypeScript type
object. Usually, it goes like this:
We define a type called Props
and inside that type, we pass all the props that our component can receive.
import React from "react";
type Props = {
name: string;
age: number;
}
const User = (props: Props) => {
return (
<div>
<h1>{props.name}</h1>
<h2>{props.age}</h2>
</div>
);
};
export default User;
It is a best practice to destructure our props object—it allows more flexibility in how we can define our props. By destructuring it, we can also pass default props. For example, imagine that we want to pass a default value to our age
prop. This is how we would do it:
import React from "react";
type Props = {
name: string;
age: number;
};
const User = ({ name, age = 21 }: Props) => {
return (
<div>
<h1>{name}</h1>
<h2>{age}</h2>
</div>
);
};
export default User;
React Context allows you to share and manage states across your components without passing down props. Similar to libraries like Redux, Context can be a great choice for sharing states across your components without having to install a library for that.
We should make use of TypeScript in our contexts and make it more reliable and safe. We can implement TypeScript in our contexts very easily:
import { createContext } from "react";
interface UserContextI {
name: string;
age: number;
}
const defaultState = {
name: "Leonardo",
age: 21
};
const UserContext = createContext<UserContextI>(defaultState);
export default UserContext;
It is a challenge for every company that decides to migrate to TypeScript, but the gradual migration can mitigate the challenges and makes the adoption easier. Remember that it is a process that can take days, weeks or months. Don’t try to rush things and make it happen all at once.
Migrating to TypeScript is a decision that will benefit a large code base in the long term. The benefits of using TypeScript with React—such as readability, maintainability and code consistency—are hard to beat.
Next up, you may want to read Using TypeScript With React and KendoReact Components or Getting Started With TypeScript and React.
Leonardo is a full-stack developer, working with everything React-related, and loves to write about React and GraphQL to help developers. He also created the 33 JavaScript Concepts.