Using TypeScript with React Native
TypeScript is a language which extends JavaScript by adding type definitions, much like
Flow. While React Native is built in Flow, it supports both TypeScript
and Flow by default.
If you're starting a new project, there are a few different ways to get started. You can use the
TypeScript template:
npx react-native init MyApp --template react-native-template-typescript
You can use
Expo which has two TypeScript templates:
npm install -g expo-cli
expo init MyTSProject
Or you could use
Ignite, which also has a TypeScript template:
npm install -g ignite-cli
ignite new MyTSProject
- Add TypeScript and the types for React Native and Jest to your project.
yarn add --dev typescript @types/jest @types/react @types/react-native @types/react-test-renderer
npm install --save-dev typescript @types/jest @types/react @types/react-native @types/react-test-renderer
- Add a TypeScript config file. Create a
tsconfig.json
in the root of your project:
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"isolatedModules": true,
"jsx": "react",
"lib": ["es6"],
"moduleResolution": "node",
"noEmit": true,
"strict": true,
"target": "esnext"
},
"exclude": ["node_modules", "babel.config.js", "metro.config.js", "jest.config.js"]
}
- Create a
jest.config.js
file to configure Jest to use TypeScript
module.exports = {
preset: 'react-native',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
};
- Rename a JavaScript file to be
*.tsx
You should leave the ./index.js
entrypoint file as it is otherwise you may run into an issue when it comes to bundling a production build.
- Run
yarn tsc
to type-check your new TypeScript files.
Out of the box, transforming your files to JavaScript works via the same
Babel infrastructure as a non-TypeScript React Native project. We recommend that you use the TypeScript compiler only for type checking. If you have existing TypeScript code being ported to React Native, there are
one or two caveats to using Babel instead of TypeScript.
You can provide an interface for a React Component's
Props and
State via
React.Component<Props, State>
which will provide type-checking and editor auto-completing when working with that component in JSX.
import React from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
export interface Props {
name: string;
enthusiasmLevel?: number;
}
const Hello: React.FC<Props> = props => {
const [enthusiasmLevel, setEnthusiasmLevel] = React.useState(props.enthusiasmLevel);
const onIncrement = () => setEnthusiasmLevel((enthusiasmLevel || 0) + 1);
const onDecrement = () => setEnthusiasmLevel((enthusiasmLevel || 0) - 1);
const getExclamationMarks = (numChars: number) => Array(numChars + 1).join('!');
return (
<View style={styles.root}>
<Text style={styles.greeting}>
Hello {props.name + getExclamationMarks(enthusiasmLevel || 0)}
</Text>
<View style={styles.buttons}>
<View style={styles.button}>
<Button title="-" onPress={onDecrement} accessibilityLabel="decrement" color="red" />
</View>
<View style={styles.button}>
<Button title="+" onPress={onIncrement} accessibilityLabel="increment" color="blue" />
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
root: {
alignItems: 'center',
alignSelf: 'center',
},
buttons: {
flexDirection: 'row',
minHeight: 70,
alignItems: 'stretch',
alignSelf: 'center',
borderWidth: 5,
},
button: {
flex: 1,
paddingVertical: 0,
},
greeting: {
color: '#999',
fontWeight: 'bold',
},
});
export default Hello;
To use custom path aliases with TypeScript, you need to set the path aliases to work from both Babel and TypeScript. Here's how:
- Edit your
tsconfig.json
to have your custom path mappings. Set anything in the root of src
to be available with no preceding path reference, and allow any test file to be accessed by using test/File.tsx
:
"target": "esnext",
+ "baseUrl": ".",
+ "paths": {
+ "*": ["src/*"],
+ "tests": ["tests/*"],
+ "@components/*": ["src/components/*"],
+ },
}
- Configure the Babel side done by adding a new dependency,
babel-plugin-module-resolver
:
yarn add --dev babel-plugin-module-resolver
npm install --save-dev babel-plugin-module-resolver
- Finally, configure your
babel.config.js
(note that the syntax for your babel.config.js
is different from your tsconfig.json
):
{
plugins: [
+ [
+ 'module-resolver',
+ {
+ root: ['./src'],
+ extensions: ['.ios.js', '.android.js', '.js', '.ts', '.tsx', '.json'],
+ alias: {
+ "tests": ["./tests/"],
+ "@components": "./src/components",
+ }
+ }
+ ]
]
}