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.
Getting Started with TypeScript#
If you're starting a new project, there are a few different ways to get started. You can use the TypeScript template:
# Template version is specifically for React Native 0.60npx react-native init MyTSProject --template react-native-template-typescript@6.2.0You can use Expo which has two TypeScript templates:
npm install -g expo-cliexpo init MyTSProjectOr you could use Ignite, which also has a TypeScript template:
npm install -g ignite-cliignite new MyTSProjectAdding TypeScript to an Existing Project#
- 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# or for npmnpm install --save-dev typescript @types/jest @types/react @types/react-native @types/react-test-renderer- Add a TypeScript config file. Create a
tsconfig.jsonin 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.jsfile to configure Jest to use TypeScript
module.exports = { preset: 'react-native', moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node']};Rename a JavaScript file to be
*.tsxRun
yarn tscto type-check your new TypeScript files.
How TypeScript and React Native works#
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.
What does React Native + TypeScript look like#
You can provide an interface for a React Component's [Props]](props) and [State]](state) via React.Component<Props, State> which will provide type-checking and editor auto-completing when working with that component in JSX.
// components/Hello.tsximport 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> ); }}
// stylesconst 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', },});You can explore the syntax more in the TypeScript playground.
Where to Find Useful Advice#
- TypeScript Handbook
- React's documentation on TypeScript
- React + TypeScript Cheatsheets has a good overview on how to use React with TypeScript
Using Custom Path Aliases with TypeScript#
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.jsonto have your custom path mappings. Set anything in the root ofsrcto be available with no preceding path reference, and allow any test file to be accessed by usingtest/File.tsx:
"target": "esnext",+ "baseUrl": ".",+ "paths": {+ "*": ["src/*"],+ "tests": ["tests/*"]+ }, }- Configure the Babel side done by adding a new dependency,
babel-plugin-module-resolver:
yarn add --dev babel-plugin-module-resolver# ornpm install --save-dev babel-plugin-module-resolver- Finally, configure your
babel.config.js(note that the syntax for yourbabel.config.jsis different from yourtsconfig.json):
{ plugins: [+ [+ 'module-resolver',+ {+ root: ['./src'],+ extensions: ['.ios.js', '.android.js', '.js', '.ts', '.tsx', '.json'],+ alias: {+ "test/*": ["./test/"],+ }+ }+ ] ]}