React Navigation is commonly used to move between screens in React Native applications. With TypeScript, we can define the available screens, navigation methods, and route parameters so that navigation code becomes safer and easier to maintain.
React Navigation is a navigation library used to create navigation between screens in React Native applications.
For example, an application may contain:
Without proper types, it is easy to navigate to the wrong screen or pass incorrect parameters.
TypeScript allows us to define exactly which screens are available and what parameters each screen expects.
React Navigation is installed as a project dependency along with the required navigation packages.
npm install @react-navigation/native
The exact additional packages depend on the navigator being used.
Stack navigation manages screens in a stack-like structure.
For example:
Home
↓
Details
↓
Profile
The user can move forward to a screen and then go back to the previous screen.
We can create a type describing the screens in our application.
type RootStackParamList = {
Home: undefined;
Details: undefined;
Profile: undefined;
};
This is one of the most important parts of typed navigation.
If a screen does not require parameters, we can use undefined.
type RootStackParamList = {
Home: undefined;
Profile: undefined;
};
This means these screens can be opened without passing route parameters.
A stack navigator can be created using React Navigation.
import { createNativeStackNavigator }
from "@react-navigation/native-stack";
const Stack =
createNativeStackNavigator<RootStackParamList>();
The generic type connects the navigator with our screen definitions.
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
/>
<Stack.Screen
name="Profile"
component={ProfileScreen}
/>
</Stack.Navigator>
The screen names are checked against the navigation type.
The navigator is normally placed inside a NavigationContainer.
import {
NavigationContainer
} from "@react-navigation/native";
export default function App(): React.JSX.Element {
return (
<NavigationContainer>
...
</NavigationContainer>
);
}
const Stack =
createNativeStackNavigator<RootStackParamList>();
export default function App(): React.JSX.Element {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
/>
<Stack.Screen
name="Profile"
component={ProfileScreen}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
A screen can use a typed navigation prop.
import {
NativeStackScreenProps
} from "@react-navigation/native-stack";
type HomeProps =
NativeStackScreenProps<
RootStackParamList,
"Home"
>;
This connects the Home screen with the navigation type.
function HomeScreen({
navigation
}: HomeProps): React.JSX.Element {
return (
<Button
title="Open Profile"
onPress={() => {
navigation.navigate("Profile");
}}
/>
);
}
TypeScript checks whether Profile is a valid screen.
navigation.navigate("Profile");
The navigate() method moves the user to another registered
screen.
Because the navigator is typed, the screen name is checked by TypeScript.
The navigation object provides a method for going back to the previous screen.
navigation.goBack();
This is commonly used with a Back button.
Screens can receive parameters when they are opened.
type RootStackParamList = {
Home: undefined;
Details: {
studentId: number;
};
};
The Details screen now requires a numeric studentId.
navigation.navigate("Details", {
studentId: 101
});
TypeScript checks that studentId is a number.
type DetailsProps =
NativeStackScreenProps<
RootStackParamList,
"Details"
>;
This type gives the Details screen typed access to both navigation and route information.
function DetailsScreen({
route
}: DetailsProps): React.JSX.Element {
const studentId =
route.params.studentId;
return (
<Text>
Student ID: {studentId}
</Text>
);
}
TypeScript knows that studentId is a number.
type RootStackParamList = {
Home: undefined;
Details: {
studentId: number;
studentName: string;
};
};
A route can contain multiple strongly typed parameters.
navigation.navigate("Details", {
studentId: 101,
studentName: "Rahul"
});
TypeScript checks both the property names and their value types.
Route parameters can also be optional.
type RootStackParamList = {
Home: undefined;
Profile: {
userId?: number;
};
};
The userId parameter may or may not be provided.
type RootStackParamList = {
Home: undefined;
Product: {
productId: string;
};
};
navigation.navigate("Product", {
productId: "P101"
});
Route parameters can use union types when only certain values are allowed.
type RootStackParamList = {
Home: undefined;
Profile: {
mode: "student" | "teacher";
};
};
Only student or teacher can be passed.
any for navigation objects.A large application can keep its navigation types in a separate file.
// navigation/types.ts
export type RootStackParamList = {
Home: undefined;
Details: {
studentId: number;
};
Profile: {
userId: string;
};
};
Other screens can import this type when needed.
NativeStackScreenProps for stack screen props.any for navigation.type RootStackParamList = {
Home: undefined;
Profile: {
userId: number;
};
Settings: undefined;
};
navigation.navigate("Profile", {
userId: 101
});
navigation.navigate("Settings");
Each screen can have its own parameter requirements.
import React from "react";
import {
View,
Text,
Button
} from "react-native";
import {
NavigationContainer
} from "@react-navigation/native";
import {
createNativeStackNavigator,
NativeStackScreenProps
} from "@react-navigation/native-stack";
type RootStackParamList = {
Home: undefined;
Details: {
studentId: number;
studentName: string;
};
};
type HomeProps =
NativeStackScreenProps<
RootStackParamList,
"Home"
>;
type DetailsProps =
NativeStackScreenProps<
RootStackParamList,
"Details"
>;
function HomeScreen({
navigation
}: HomeProps): React.JSX.Element {
return (
<View>
<Text>
Home Screen
</Text>
<Button
title="Open Student"
onPress={() => {
navigation.navigate(
"Details",
{
studentId: 101,
studentName: "Rahul"
}
);
}}
/>
</View>
);
}
function DetailsScreen({
route,
navigation
}: DetailsProps): React.JSX.Element {
return (
<View>
<Text>
Student ID: {route.params.studentId}
</Text>
<Text>
Name: {route.params.studentName}
</Text>
<Button
title="Go Back"
onPress={() => {
navigation.goBack();
}}
/>
</View>
);
}
const Stack =
createNativeStackNavigator<
RootStackParamList
>();
export default function App(): React.JSX.Element {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
/>
<Stack.Screen
name="Details"
component={DetailsScreen}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
Typed navigation makes screen-to-screen communication safer. TypeScript can identify invalid screen names, missing parameters, and incorrect parameter types during development.
TypeScript makes React Navigation safer by allowing us to define screen names and route parameters. The navigation object and route object can then be strongly typed for individual screens.
You should now understand typed stack navigation, navigation props, route props, route parameters, optional parameters, union types, and reusable navigation types.
undefined for screens without parameters.NativeStackScreenProps to type stack screens.navigation.navigate() to move between screens.navigation.goBack() to return to the previous screen.Question: Which type is commonly used to define the parameters for screens in a typed React Navigation stack?