Skip to main content
Version: 5.x

Type checking with TypeScript

React Navigation is written with TypeScript and exports type definitions for TypeScript projects.

Type checking the navigator

To type check our route name and params, the first thing we need to do is to create an object type with mappings for route name to the params of the route. For example, say we have a route called Profile in our root navigator which should have a param userId:

type RootStackParamList = {
Profile: { userId: string };
};

Similarly, we need to do the same for each route:

type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Feed: { sort: 'latest' | 'top' } | undefined;
};

Specifying undefined means that the route doesn't have params. A union type with undefined (e.g. SomeType | undefined) means that params are optional.

After we have defined the mappings, we need to tell our navigator to use it. To do that, we can pass it as a generic to the createXNavigator functions:

import { createStackNavigator } from '@react-navigation/stack';

const RootStack = createStackNavigator<RootStackParamList>();

And then we can use it:

<RootStack.Navigator initialRouteName="Home">
<RootStack.Screen name="Home" component={Home} />
<RootStack.Screen
name="Profile"
component={Profile}
initialParams={{ userId: user.id }}
/>
<RootStack.Screen name="Feed" component={Feed} />
</RootStack.Navigator>

This will provide type checking and intelliSense for props of the Navigator and Screen components.

Type checking screens

To type check our screens, we need to annotate the navigation prop and the route prop received by a screen.

To annotate the navigation prop, we need to import the corresponding type from the navigator. For example, StackNavigationProp for @react-navigation/stack:

import { StackNavigationProp } from '@react-navigation/stack';

type ProfileScreenNavigationProp = StackNavigationProp<
RootStackParamList,
'Profile'
>;

type Props = {
navigation: ProfileScreenNavigationProp;
};

The type for the navigation prop takes 2 generics, the param list object we defined earlier, and the name of the current route. This allows us to type check route names and params which you're navigating using navigate, push etc. The name of the current route is necessary to type check the params when you call setParams.

Similarly, you can import DrawerNavigationProp from @react-navigation/drawer, BottomTabNavigationProp from @react-navigation/bottom-tabs etc.

To annotate the route prop, we need to use the RouteProp type from @react-navigation/native:

import { RouteProp } from '@react-navigation/native';

type ProfileScreenRouteProp = RouteProp<RootStackParamList, 'Profile'>;

type Props = {
route: ProfileScreenRouteProp;
};

This allows us to type check the route object, such as route.params.

To summarize:

import { RouteProp } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';

type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Feed: { sort: 'latest' | 'top' } | undefined;
};

type ProfileScreenRouteProp = RouteProp<RootStackParamList, 'Profile'>;

type ProfileScreenNavigationProp = StackNavigationProp<
RootStackParamList,
'Profile'
>;

type Props = {
route: ProfileScreenRouteProp;
navigation: ProfileScreenNavigationProp;
};

Alternatively, you can also import a generic type to define types for both the navigation and route props from the corresponding navigator:

import { StackScreenProps } from '@react-navigation/stack';

type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Feed: { sort: 'latest' | 'top' } | undefined;
};

type Props = StackScreenProps<RootStackParamList, 'Profile'>;

Similarly, you can import DrawerScreenProps from @react-navigation/drawer, BottomTabScreenProps from @react-navigation/bottom-tabs etc.

Then you can use the Props type to annotate your component.

For function components:

function ProfileScreen({ route, navigation }: Props) {
// ...
}

For class components:

class ProfileScreen extends React.Component<Props> {
render() {
// ...
}
}

We recommend creating a separate types.tsx file where you keep the types and import them in your component files instead of repeating them in each file.

Nesting navigators

Type checking screens and params in nested navigator

You can navigate to a screen in a nested navigator by passing screen and params properties for the nested screen:

navigation.navigate('Home', {
screen: 'Feed',
params: { sort: 'latest' },
});

To be able to type check this, we need to extract the params from the screen containing the nested navigator. This can be done using the NavigatorScreenParams utility:

import { NavigatorScreenParams } from '@react-navigation/native';

type TabParamList = {
Home: NavigatorScreenParams<StackParamList>;
Profile: { userId: string };
};

Combining navigation props

When you nest navigators, the navigation prop of the screen is a combination of multiple navigation props. For example, if we have a tab inside a stack, the navigation prop will have both jumpTo (from the tab navigator) and push (from the stack navigator). To make it easier to combine types from multiple navigator, you can use the CompositeNavigationProp type:

import { CompositeNavigationProp } from '@react-navigation/native';
import { BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
import { StackNavigationProp } from '@react-navigation/stack';

type ProfileScreenNavigationProp = CompositeNavigationProp<
BottomTabNavigationProp<TabParamList, 'Profile'>,
StackNavigationProp<StackParamList>
>;

The CompositeNavigationProp type takes 2 parameters, first parameter is the primary navigation type (type for the navigator that owns this screen, in our case the tab navigator which contains the Profile screen) and second parameter is the secondary navigation type (type for a parent navigator). The primary navigation type should always have the screen's route name as its second parameter.

For multiple parent navigators, this secondary type should be nested:

type ProfileScreenNavigationProp = CompositeNavigationProp<
BottomTabNavigationProp<TabParamList, 'Profile'>,
CompositeNavigationProp<
StackNavigationProp<StackParamList>,
DrawerNavigationProp<DrawerParamList>
>
>;

Annotating useNavigation

To annotate the navigation prop that we get from useNavigation, we can use a type parameter:

const navigation = useNavigation<ProfileScreenNavigationProp>();

It's important to note that this isn't completely type-safe because the type parameter you use may not be correct and we cannot statically verify it.

Annotating useRoute

To annotate the route prop that we get from useRoute, we can use a type parameter:

const route = useRoute<ProfileScreenRouteProp>();

It's important to note that this isn't completely type-safe, similar to useNavigation.

Annotating options and screenOptions

When you pass the options to a Screen or screenOptions prop to a Navigator component, they are already type-checked and you don't need to do anything special. However, sometimes you might want to extract the options to a separate object, and you might want to annotate it.

To annotate the options, we need to import the corresponding type from the navigator. For example, StackNavigationOptions for @react-navigation/stack:

import { StackNavigationOptions } from '@react-navigation/stack';

const options: StackNavigationOptions = {
headerShown: false,
};

Similarly, you can import DrawerNavigationOptions from @react-navigation/drawer, BottomTabNavigationOptions from @react-navigation/bottom-tabs etc.

Annotating ref on NavigationContainer

When adding a ref to NavigationContainer, you can use the NavigationContainerRef type to annotate it.

Example when using React.useRef hook:

import { NavigationContainerRef } from '@react-navigation/native';

// ...

const navigationRef = React.useRef<NavigationContainerRef>(null);

Example when using React.createRef:

import { NavigationContainerRef } from '@react-navigation/native';

// ...

const navigationRef = React.createRef<NavigationContainerRef>();