Going Pro: Job-Ready React NativeExtra· 45 min read

TypeScript in React Native

TypeScript is the default for React Native jobs — add type labels to props, state and navigation so the editor catches mistakes before the app even runs.

What you will learn

  • Type a component’s props with an interface
  • Type useState so the value stays the right shape
  • Type navigation route params so screens cannot get bad data

Why every job asks for TypeScript

TypeScript is JavaScript with types — tiny labels that say what kind of value something is (a number, a string, a list of users). The editor reads those labels and warns you the moment you use a value the wrong way, before the app runs on a phone. In 2026, almost every React Native job description lists TypeScript, and most paid courses teach it from the first lesson. A JavaScript-only app is below the current hiring bar.

The good news: you already know React Native. TypeScript does not change how components, props or useState work — it just lets you describe what each one holds so mistakes get caught early. Think of it as a spell-checker for your data.

Expo projects come TypeScript-ready: name your files .tsx (a .tsx file is a TypeScript file that also contains JSX, the <View>-style markup) instead of .js, and you are typing. New Expo apps already include the small tsconfig.json settings file for you.

Typing props with an interface

A component’s props are the values passed into it, like <Greeting name="Aanya" />. In TypeScript you first describe the shape of those props with an interface (a named list of fields and their types), then tell the component to use it. Here is a small greeting card that expects a name string and an age number:

An interface describes the props; the component is typed with it
import { View, Text } from 'react-native';

interface GreetingProps {
  name: string;
  age: number;
}

function Greeting({ name, age }: GreetingProps) {
  return (
    <View>
      <Text>Hi {name}, you are {age} years old.</Text>
    </View>
  );
}

// Using it:
<Greeting name="Aanya" age={20} />

Note: Output: On the phone: Hi Aanya, you are 20 years old. If you wrote <Greeting name="Aanya" /> (forgetting age), or age="20" (a string instead of a number), the editor underlines it in red before you ever run the app and tells you exactly what is wrong.

Line by line, what the interface bought us:

  • interface GreetingProps { ... } names a shape: a name that must be a string and an age that must be a number.
  • { name, age }: GreetingProps tells the component "the props you receive match this shape" — so inside, name is known to be a string and age a number.
  • Anyone using <Greeting /> now gets autocomplete for the props and a clear error if they pass the wrong thing or forget one.

Typing useState

Most of the time TypeScript figures out the type of a useState on its own from the starting value. useState(0) is clearly a number; useState('') is clearly a string. You only add a type yourself when the starting value does not tell the whole story — for example an array that starts empty, or a value that might be missing.

Here we keep a list of users. It starts as an empty array [], which on its own does not say what the array holds, so we spell it out with useState<User[]> (read: "state holding an array of User"):

useState<User[]> says the state is an array of User objects
import { useState } from 'react';

interface User {
  id: number;
  name: string;
}

const [users, setUsers] = useState<User[]>([]);

// Later — this is allowed:
setUsers([{ id: 1, name: 'Aanya' }]);

// This is caught as an error:
setUsers([{ id: 1, title: 'Aanya' }]);

Note: Output: No screen output — this is about safety. The second setUsers is underlined in red: a User needs a name, not a title. TypeScript stops you from saving the wrong shape, which would otherwise crash later when you read user.name.

Typing navigation route params

Remember passing data between screens with route.params? Without types, nothing stops you from reading a param that was never sent, which crashes at runtime. TypeScript lets you list every screen and the params it expects in one place, so the editor checks both the navigate call and the route.params read.

You create a type that maps each screen name to its params. undefined means "this screen takes no params":

One param-list type makes navigation fully type-checked
import { NativeStackScreenProps } from '@react-navigation/native-stack';

// 1) List every screen and the params it expects
type RootStackParamList = {
  Home: undefined;
  Details: { itemId: number; itemName: string };
};

// 2) Type one screen's props from that list
type DetailsProps = NativeStackScreenProps<RootStackParamList, 'Details'>;

function DetailsScreen({ route }: DetailsProps) {
  // route.params is now known to have itemId and itemName
  return <Text>You picked {route.params.itemName}</Text>;
}

Note: Output: On the phone (when navigated to with an item): You picked Milk Now navigation.navigate('Details', { itemId: 1, itemName: 'Milk' }) is checked too — forget itemId or send a string where a number belongs and the editor flags it. And route.params.itemNme (a typo) is caught instead of silently being undefined.

How the pieces fit together, step by step

Here is the whole "add TypeScript" journey for a screen, in order, so you can repeat it on any component:

  1. Name your file .tsx so it accepts both types and JSX.
  2. Write an interface (or type) describing the props the component receives — each field and its type.
  3. Annotate the component’s parameter with that interface: function Screen({ ... }: ScreenProps).
  4. For state, let TypeScript infer simple values; add useState<Shape>(...) only when the starting value is empty or could be missing.
  5. For navigation, write one ParamList type mapping screen names to their params, and type each screen with NativeStackScreenProps.
  6. Watch the editor: red underlines now appear the instant a value has the wrong shape — fix them before you ever open the app on a phone.

Tip: Prefer typing data shapes (props, API responses, route params) first — that is where wrong-shape bugs hurt most. You rarely need to type every local variable; TypeScript infers most of them for you.

Watch out: A red underline is a compile-time warning, not a crash. The app can still run with type errors during development, but you should fix them — an ignored type error is a real bug waiting to bite a user later.

Q. Why do you sometimes write useState<User[]>([]) instead of just useState([])?

Answer: An empty [] gives TypeScript no clue about the item shape, so you spell it out with useState<User[]> to keep the array type-safe.

✍️ Practice

  1. Add a ProfileProps interface (name: string, isOnline: boolean) and type a Profile component with it.
  2. Type a useState that starts as null and later holds a User object (hint: useState<User | null>(null)).

🏠 Homework

  1. Convert one screen from an earlier lesson to .tsx: add a props interface, type its useState, and fix every red underline the editor shows.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →