DEV Community

Ryohlan
Ryohlan

Posted on

Type safe navigation for react-navigation v5

First, I show my type-definitions.

// Define screens. The key is a screen name. The value is a parameter passed to a navigation object.
export type Screens = {
}

// Define your navigators.
export type Navigators = {
}

type Navigatable<T> = T extends keyof Screens
  ? ScreenParams<T>
  : T extends keyof Navigators
  ? NavigatorParams<T>
  : never

type ScreenParams<T extends keyof Screens> = {
  screen: T
  params: Screens[T]
}

type NavigatorParams<T extends keyof Navigators> = {
  screen: T
  params: Navigators[T]
}

export type NavigationParams = Screens & Navigators

export type TypedNavigatorParams<T extends keyof Navigators> = Pick<
  NavigationParams,
  NavigationParams[T]['screen']
>

Usage

Read my repository for detail.

https://github.com/ryohlan/typesafe-react-navigation-sample

if you are considering the following structure:

AppNavigator 
 - AuthNavigator
  - launch
  - signup
 - MainNavigator
  - MainTabNavigator
   - home
   - search

You can define the Screens and the Navigators the following:

// Define screens. The key is a screen name. The value is a parameter passed to a navigation object.
export type Screens = {
 launch: {}
 signup: { signupParam: string }
 home: {}
 search: { searchParam: number }
}

// Define your navigators.
export type Navigators = {
  AppNavigator: Navigatable<'AuthNavigator' | 'MainNavigator'>
  AuthNavigator: Navigatable<'launch'|'signup'>
  MainNavigator: Navigatable<'MainTabNavigator'>
  MainTabNavigator: Navigatable<'home'|'search>
}

A Navigator also can be checked:

import React from 'react'
import { createStackNavigator } from '@react-navigation/stack'
import { TypedNavigatorParams } from './NavigationParams'
import { LaunchScreen } from '../screens/LaunchScreen'

const { Screen, Navigator } = createStackNavigator<TypedNavigatorParams<'AuthNavigator'>>()

export const AuthNavigator = () => {
  return (
    <Navigator mode="card">
      <Screen {...LaunchScreen} />
    </Navigator>
  )
}

And create custom hooks for navigation.

import { useNavigation as useDefaultNavigation } from '@react-navigation/core'
import { StackNavigationProp } from '@react-navigation/stack'
import { NavigationParams } from '@src/components/navigators/NavigationParams'

export const useNavigation = () => useDefaultNavigation<StackNavigationProp<NavigationParams>>()

You can navigate type-safely using useNavigation!

const navigation = useNavigation()
navigation.navigate('AppNavigator', {
  screen: 'AuthNavigator',
  params: {
    screen: 'signup',
    params: { signupParam: '' }, // If
  },
})

Top comments (0)