React Native and Typescript

The main intention of this blog post is to show how to setup a React Native project with a Typescript environment as an alternative to Flow.

EDIT: This guide is outdated. Please go to the updated repository: https://github.com/mrpatiwi/ReactNativeTS

Go ahead and install Node.js and the required tools from the official install guide: https://facebook.github.io/react-native/docs/getting-started.html#content

A more complete example code and starting point is available here:

Up next, we will setup the most basic React Native application with Typescript.


Environment

The most adequate IDE is Visual Studio Code, this doesn’t means you can’t use your favorite IDE. Just make sure you have a Typescript-related plugin, like atom-typescript for Atom.

Preview of the final result with Visual Studio Code

Dependencies

Along with react-native-cli, we will need:

Install all the required dependencies with:

npm install -g typescript tslint typings react-native-cli

Creating the app

Starting a React Native app is very straightforward:

# Create app
react-native init ReactNativeTS
# Navigate to the just created app
cd ReactNativeTS
# Start git
git init

It’s a good practice to have the Typescript-related dependencies at the package.json file, so:

npm install --save-dev typescript tslint typings

To start a Typescript project and avoid long commands on the terminal, it’s good to have a tsconfig.json file.

Also, we need to keep track of the required typings, because they are not always bundled in the dependency itself, we will use Typings:

tsc --init
typings init

The default config files should look like this:

Typings

Let’s find the typings of React Native. We can use the cli as follow:

typings search react-native

So, we found some typings, but they are written for DefinitelyTyped. To install them with Typings and move forward with the React typings we run:

typings install dt~react dt~react-native --save --global

The dt keyword has the meaning of telling the cli to use the definitions from DefinitelyTyped. The global flag is required for this cases.

Typescript config

Time to setup out tsconfig.json file. Here are declared all the required info to tell Typescript transpiler how to build our app. We will use the following settings:

  • Our target JS will be ES2015, because React Native supports it by default. Also we want to use JSX syntax and be able to include Javascript files along with Typescript files.
  • Out source code will be located at src directory and the output JS files will be placed at the build directory.
  • We want to follow as much as possible the Babel import system. That’s why we will activate allowSyntheticDefaultImports.

The recommended tsconfig.json file should be like this:

Don’t forget to add the following to your .gitignore:

# .gitignore
build
typings

Prepare React Native app

To easily support Typescript, let’s create the main entrance of our app at the src directory:

mkdir src
touch src/index.tsx

As a minimal working example, our main component will be as next:

A few notes about this:

  • We import React and React Native modules as always.
  • Our IDE should capable of showing autocomplete for types and show warnings and errors.
  • Component must have a State and Props interfaces. If empty, you can always use the any type.
  • The styles must have typings.

To see how Typescript is transpiling our new components, run:

tsc
This automatically reads the tsconfig.json file.

The final JS file is placed at build/index.js:

Transpiled Javascript file from Typescript source

You can see this is a common React Native Javascript file. The typings and interfaces are removed and the JSX syntax in converted to normal Javascript.


Putting it all together

Currently, the main index files:

  • index.android.js
  • index.ios.js

Are not pointing to our new base components. We should edit them as follow:

This implies that we expect to have built the TS source before running the app on a device or emulator.

Also I recommend to have the following scripts in the package.json file:

"scripts": {
"preinstall": "rm -rf typings",
"postinstall": "node node_modules/typings/dist/bin.js install",
"start": "node node_modules/react-native/local-cli/cli.js start",
"android": "node node_modules/react-native/local-cli/cli.js run-android",
"ios": "node node_modules/react-native/local-cli/cli.js run-ios",
"prebuild": "rm -rf build",
"build": "tsc"
},

Open two terminals and run:

# One terminal for build and watch for changes
npm run build -- --watch
# Other terminal to run the development server
npm start

iOS & Android

Open another terminal (sorry!) to run it on a iOS emulator:

npm run ios

To run it on Android, be sure to follow the install instructions from:

https://facebook.github.io/react-native/docs/getting-started.html#dependencies-for-android

Now, any change made to the contents of the src directory will update the JS files. So Hot Reloading must be working well right now.

To build the source without watching is simple as:

npm run build

Adding custom components

It’s all about components and it rich ecosystem available to developers. So I will show how to add third-party modules and make them work with Typescript. Because — let’s be honest — there should be none React Native components written in Typescript with typings.

As an example, let’s take:

npm install --save react-native-button

Creating the 100% perfect typings is a hard and unnecessary work. So we can do the following:

touch src/declarations.d.ts

If we use the any type, Typescript will not bother us about missing typings or wrong usage:

It’s easy and we get (rotated screen to show it better here at Medium):

It’s possible to improve the declared typings, take as example:

The usage still the same.

There are not the full typings of the components, but you can see that we can make improvements over the time.

Conclusion

The usage with Typescript is very simple. But it comes with risks:

  • React (Facebook) has Flow. Even if it’s a annotation system, I think the invention of this has splitted the community. We could have a unique and common typings system for React and Angular. Maybe someday a combination of both of this technologies will be merged to the ECMAScript.
  • It’s hard to find modules with typings. Un-official support comes with compatibility problems because of outdated or incomplete typings.
  • The typings conventions are still immature, so it’s common to have errors and it’s hard to find updated information and guides.
  • Perhaps it’s better to stick with Flow or keep using classic un-typed Javascript.

Finally, a more complete example code is available at: