React with TypeScript in 2019
My journey started almost four years ago in September 2015. That's when I first started exploring the upcoming support of JSX syntax in TypeScript, and I have written a post about it.
Since then, the post remained mostly unmaintained. I’ve added a few edits to nudge people in the right direction.
Of course, a lot has changed in this time. Both TypeScript and React grew more mature and received significant improvements. Both React and the TypeScript team are still doing an excellent job of providing a pleasant development experience.
How it used to be "in the old days" 📟
When I was starting in late 2015, I couldn’t find a satisfying boilerplate project, so I've started one from scratch.
There was also no useful tools to convert JSX files to TypeScript's TSX. At that time, I've created a rudimentary
js-to-tsx script to rename files. It required lots of manual work, but at least the compiler caught the errors and helped you along the way.
@types/* didn't exist back then. The DefinitelyTyped project was a thing even back then, but managing the types required an external CLI tool called
tsd. So being efficient with TypeScript required learning another tool, and adding additional project setup.
Creating a new project 🎉
These days, I see no need for a boilerplate project like the one mentioned before. When starting a new React + TypeScript project, I get the job done with
create-react-app using the
--typescript flag. Everything comes configured out-of-the-box so you can get to work right away.
npx create-react-app --typescript works without having to install create-react-app. The
npx command useful if you rarely use a CLI tool and don’t want to pollute your system.
Earlier this year, I was leading the introduction of TypeScript to our existing medium-sized (~100k LOC) React project. The process was much smoother compared to my experience from 2015 when the TypeScript team just announced the support for JSX. And at that time, I was only using it for personal projects; I would not be comfortable using it on any production project.
The type declaration (
The easy way to do it is to keep the source code as-is and add
MyComponent.d.ts type declaration file next to your
But I don't like this approach. I see this as a comment describing the code. It's easy to edit the source code and forget to update the type declaration file. The TypeScript code does not know that something changed, so the compiler will not warn you about it, and you'll get a runtime error. I prefer converting the code to TypeScript and let it speak for itself.
A more robust, but also more time-consuming approach is to convert
MyComponent.jsx to TypeScript as
MyComponent.tsx. This way, you don't have to worry about keeping the declaration files in sync with code, the code is the declaration file.
Caveat: some code is complex and makes the conversion to proper types time-consuming. In addition to that, the API rarely changes. These conditions are a good argument not to convert the code and make use of
For the files you decide to convert, you can speed up the process and make it a bit less painful by using
react-js-to-ts. You can use it as
npx react-js-to-ts MyComponent.jsx
It reads the React source code, and it knows what different
PropTypes mean in the TypeScript world. It automatically generates a
type declaration for
state. It outputs the converted component at
MyComponent.tsx and removes the
It's a good idea to use version control, or to at least back up the
.jsx files before you start the process, just in case.
The tool is not perfect, and it can mess up on non-trivial
propTypes usages, but it's much more useful than my
js-to-tsx script. There's also a VSCode plugin to run it directly from your editor.
Typings for dependencies
For new and existing projects alike, external libraries and components are bound to come into play. To get the full power of TypeScript, it makes sense to have typings for used dependencies.
Some projects ship with typings out of the box. The compiler, and in extension your editor plugin, will pick these up automatically. For projects which do not include it, there's the DefinitelyTyped project, which provides typings for a lot of
npm projects and makes these typings available on
@types/[project]. Adding these typings, for example, for
react, is as easy as
npm i -D @types/react # or with yarn yarn add -D @types/react
TypeScript knows where to look for these types, so you don't have to configure anything.
Something to keep in mind is if you're not using the latest version of a dependency, make sure to use the corresponding version of typings.
TypeScript and React came a long way since in 2015 when TypeScript introduced support for JSX. It's now easier to get started with a new project and to convert an existing project.
To start a new project, use
npx create-react-app --typescript.
When converting an existing project,
react-js-to-ts can be useful. Or you can add
.d.ts files to the existing JSX components.