typescriptreact-nativereact-navigationreact-navigation-stack

How to properly type useNavigation in React Navigation?


I'm trying to type the useNavigation from React Navigation. I would like to be able to pass only the name of the route, but I get an error unless I also pass props for that route.

Following the documentation, I understand the implementation should look something like this:

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

type StackParamList = {
    Home: { foo: string, onBar: () => void }
    About: AboutProps
}

type NavigationProps = StackNavigationProp<StackParamList>

const MyComponent = () => {
  const navigation = useNavigation<NavigationProps>()

  const handleOnNavigate = () => navigation.navigate('Home')
  //                                                    ^ TypeError!

I am geting a TypeError on the last line there. If I add the props for that route, the error disappears, but I shouldn't have to do that.

navigation.navigate('Home', { foo: 'hello', onBar: () => {} })

Looking at the type declaration for navigation.navigate (see below), this should not be necessary, as there is an overload for simply passing the name of the route as the only argument. I must be doing something wrong, since that is not accepted ... but what, where and why?

Here is a CodeSandBox reproducing the TypeError.

React Navigation types.d.ts (link)

navigate<RouteName extends keyof ParamList>(...args: undefined extends ParamList[RouteName]
  ? [screen: RouteName] | [screen: RouteName, params: ParamList[RouteName]]
  : [screen: RouteName, params: ParamList[RouteName]])
: void;

Solution

  • I am geting a TypeError on the last line there. If I add the props for that route, the error disappears, but I shouldn't have to do that.

    You specified this in types:

    Home: { foo: string, onBar: () => void }
    

    Which means Home takes these params. If your route doesn't take any params and you could just do navigate('Home'), you shouldn't be specifying any params in the types.

    If those params are optional, then you need to specify the type accordingly:

    Home: { foo: string, onBar: () => void } | undefined