React-Native with Typescript
Part 1 - Creating new React-Native app│Story 05: Adding Typescript
[Updated August 07, 2021]
In the previous posts of this Part-I of the series, we initialized a new react-native project, added icons for the app to iOS and Android folders as required for publishing the app to respective stores and also configured semantic versioning for the app releases.
In this post, we will configure the project to allow us to code our app in Typescript.
You can skip this story/post if you don’t wish to add Typescript for your app development to go to part II of the series to read the steps for manually releasing the app to Google Play store.
Or to Part-III to if you already have a manual release created for the app on Google Play console and are looking to see how to automate the app’s bundling and release using Gitlab CI-CD pipeline and GPP.
Adding Typescript to a react-native project - Template options
Both Expo and React-Native CLI provide templates to have your app project initialized with Typescript like below:
npx react-native init MyRNProjectName --template react-native-template-typescript
However I somehow don’t find the folder structure scaffolded by these templates very convenient and prefer to add typescript in the usual way instead of using templates.
Adding Typescript manually with no templates
Install dependencies
On your terminal/command prompt window, with pwd as project’s root folder, start with below commands
yarn add typescript @types/react @types/react-native @types/react-dom @types/prop-types -D
We’ll also need rimraf
and concurrently
to clean the output folder for ts-transpiled-to-js files and concurrently running npm/yarn scripts:
yarn add concurrently rimraf -D
For writing Jest unit tests in typescript we will need ts-jest
. We’ll also install type-defs for Jest and React test renderers:
yarn add ts-jest @types/jest @types/react-test-renderer -D
Configuration
Set up your Typescript config file (tsconfig.json
) using the tsc
command, or simply create the file manually within the project folder.
$ tsc --init
(If tsc command is failing for you, with an error like tsc command not found
, check whether you have Typescript installed globally and /node/bin
in your $PATH
var — see https://stackoverflow.com/a/37092975 or https://stackoverflow.com/a/37117612 or https://stackoverflow.com/a/46222888) for more information.)
tsconfig.json
Open the project in your code editor and update tsconfig.json
to something like here:
👆Note the settings rootDir
and outDir
(line #6-7)
above.
We’d like to store all our Typescript app code files in folders/subfolders under the src
folder. With “rootDir”: “src"
, the Typescript compiler will look for all the .ts
or .tsx
files within the src
folder and its subfolders.
“outDir”: “build”
means Typescript will output the transpiled Javascript files under build
folder.
Also note the “exclude”
property above (lines 75–85)
: any JS files or folders that you want Typescript to ignore can be added here.
Create 𝚜𝚛𝚌 and 𝚋𝚞𝚒𝚕𝚍 folders
Since we configured src
and build
as rootDir
and outputDir
in the tsconfig.json
, create these folders under our project’s root folder:
📁 Create a folder src
under project’s root folder.
📂 Create a folder build
under project’s root folder.
📂 Create a folder App
under src
folder.
When we created the project with the react-native cli’s init
command (react-native init your_project_name
), it added an App.js
under our project’s root folder.
📄 Move App.js
file to the src/App folder we created
- Rename App.js
to App.tsx
.
We would maintain the unit tests of our react components in the same folder of the component.
When react-native’s init
command scaffolded the project, it created a __tests__
folder under project’s root folder and the App
components test file (App-test.js)
under it; we would move this App test file to same folder where we store App.tsx
file i.e. under src/App/
folder and rename it to App.spec.tsx
. Remove the __tests__
folder from under the project’s root folder.
With above changes, update the file path of App.js
in the respective import statements in <<project root folder>>/index.js
and src/App/App.spec.tsx
as shown in below screenshot 👇
At this point, your project folder and files should look something like this:
Defining React$Node type for typescript
In the initial scaffolded version of App.js
, that we have now renamed to App.tsx
, you would notice it uses the Flow type Node (or in previous versions React$Node
) like below, which won’t work with typescript.
Let’s define React$Node
type for our typescript app.
Add a folder, TypesAndInterfaces
under src
. Add a file AppTypes.ts
under this folder with below code:
export type React$Node = JSX.Element | null;
Update 𝙰𝚙𝚙.𝚝𝚜𝚡
Now, update App.tsx
as below: (the initial contents scaffolded App.tsx may vary based on the ReactNative version you have)
👆 we removed the import statement for Flow type {Node} import type {Node} from 'react'
line #11
: imported the typescript type React$Node
from AppTypes.ts
that we created above.
line # 21–24
: defined type for the Section
component’s prop types
line # 26
: updated the parameter type and return type for the Section
component’s function
line # 52
: updated the return type for the App
component’s function
line #70–72
: added a new section to the screen to indicate the app is now using Typescript
𝚝𝚢𝚙𝚒𝚗𝚐𝚜.𝚍.𝚝𝚜
Based on your React-Native version, you may or may not see a global variable used in your App.tsx
. Typescript will throw an error for this global
variable being not found.
Such variables can be declared in a file typings.d.ts
, that typescript would refer to when transpiling the code.
Add a file src/typings.d.ts
and add the declare var global: any
to it.
With above declaration of global in src/typings.d.ts
, the error for global
variable being not found in App.tsx
should be gone now 👇
(Note if you are getting below errors, try rm -rf node_modules && rm -rf yarn.lock && yarn install
. If the error still exists, this might be fix for your issue 👇)
Add a few more scripts in 𝚙𝚊𝚌𝚔𝚊𝚐𝚎.𝚓𝚜𝚘𝚗
When we created the project with react-native cli’s init
command, the package.json
file it created in the scaffolded project folder contained these scripts:
...
"scripts": {
"android": "npx react-native run-android",
"ios": "npx react-native run-ios",
"start": "npx react-native start",
"test": "jest",
"lint": "eslint .",
}
...
Now, we’ll update/add few more scripts like below to run our tasks to compile Typescript, create the build and start our app:
Add above scripts to package.json
’s scripts section. These are explained below:
Running updated app on Android and iPhone:
yarn run buildRunIOS
and/or run on android running below on another terminal window:
yarn run buildRunAndroid
(Sometimes you may run into variety of issues when running on iOS/Android based on your system configuration/settings and version compatibility between the resources. Googling for those should find you the fixes)
(I first got below error for iOS)
https://stackoverflow.com/a/63538365 — didn’t work
Next, I tried the command npx react-native run-ios
, and it successfully built and ran the app on the iOS emulator device:
After this, I tried removing the app from the emulator and using our buildRunIOS
command again. This time the command worked without any issues:
If everything goes fine, the app should build successfully and load in the emulator/phone:
Configure Jest unit tests to use Typescript
Earlier we installed ts-test
package to our project allow us to write our Jest unit tests using Typescript.
Add a new file jest.config.js
under the project’s root folder like here:
👆In the testRegex
setting above, we’re specifying that it should look for any file under __test__ folder or any .test
or .spec
file under /src/ folder. We’ll put all our development source code under the src
folder, and the spec/test file will go in the subfolders under src
along with the resource/component.
Add 𝚓𝚎𝚜𝚝.𝚌𝚘𝚗𝚏𝚒𝚐.𝚝𝚜 to 𝚝𝚜𝚌𝚘𝚗𝚏𝚒𝚐.𝚓𝚜𝚘𝚗’s exclude
array
Add jest.config.ts
to tsconfig.json’s exclude
array for Typescript to ignore this file. (you may already have it in the excluded array if you copied it from the tsconfig.json
gist provided above.)
Remove jest settings from 𝚙𝚊𝚌𝚔𝚊𝚐𝚎.𝚓𝚜𝚘𝚗
Now that we have the jest configuration in a separate config file for jest, remove its configuration from package.json
.
Also, update the test
script in package.json
to run jest with the above created config file:
...
...
scripts: {
...
...
"test": "jest --config=jest.config.js",
...
...
},
...
...
Configure 𝚝𝚜-𝚓𝚎𝚜𝚝 to handle synthetic imports
React-Native uses synthetic default imports in the app component file it creates when scaffolding the project. Thus you’ll see React imported like below in App.tsx
:
import React from 'react';
For ts-jest to handle synthetic default imports, make sure you have this configuration:
In tsconfig.json
, make sure you have "allowSyntheticDefaultImports": true
under compilerOptions.
Adding a new component - 𝚂𝚎𝚌𝚝𝚒𝚘𝚗𝙷𝚎𝚊𝚍𝚎𝚛, and its unit test, coded with Typescript
📂 Create a folder components
under src
, we would store subfolders for each of our app’s components under this folder.
📂 Create a folder SectionHeader
under src/components
,
Under src/components/SectionHeader,
create a file SectionHeader.tsx
as below 👇
Add unit test for 𝚂𝚎𝚌𝚝𝚒𝚘𝚗𝙷𝚎𝚊𝚍𝚎𝚛 component
Under src/components/SectionHeader,
create a file SectionHeader.spec.tsx
as below:
Add the 𝚂𝚎𝚌𝚝𝚒𝚘𝚗𝙷𝚎𝚊𝚍𝚎𝚛 component to our App component
Update the src/App/App.tsx
file to use the SectionHeader component that we created above 👇
👆 Note line# 37–39
above: We added SectionHeader component to our App component.line # 19
: importing the SectionHeader component
Also, line# 81–83
, we added style for the SectionHeader container.
Running the App updated with 𝚂𝚎𝚌𝚝𝚒𝚘𝚗𝙷𝚎𝚊𝚍𝚎𝚛:
If you had the app already running on the devices/emulators, it should automatically refresh the view, else run the build commands for iOS and Android to run the app on respective devices/emulators.
$ yarn run buildRunAndroid
$ yarn run buildRunIOS
The App should now have our new SectionHeader component:
Configure typescript and git to ignore unit tests coverage folder
📌 Add coverage
to the exclude array of tsconfig.json
📌 Add /coverage
to your .gitignore
Running the unit tests
Run the test and make sure our typescript unit tests are running as expected: yarn test
or yarn test --coverage
.
Super! Now we can code our react-native app with Typescript. 🎉 Happy typing React-Native!
Next, we will quickly set up ESLint and Prettier in our project for Code formatting and linting, before moving on to the Part II of this series (Manual set up of the app’s first release to Google Play console)
←Prev: Icons, Semantic versioning
┈ 🏠 ┈ Next: ESLint and Prettier
→