typescriptreact-nativereact-navigationreact-navigation-stackreact-navigation-bottom-tab

TypeScript Error with Nested Navigators in React Navigation


I'm working on a React Native project using TypeScript and React Navigation. I have a nested navigator setup where I have a BottomTabNavigator which contains a BlocklistStackNavigator. I'm facing a TypeScript error when trying to assign a component to a screen in the BlocklistStackNavigator. The error message is as follows:

TS2322: Type
({ navigation, route }: Readonly<EditBlocklistScreenProps>) => Element
is not assignable to type
ScreenComponentType<ParamListBase, BlocklistsStackScreens.EDIT_BLOCKLIST> | undefined
Type
({ navigation, route }: Readonly<EditBlocklistScreenProps>) => Element
is not assignable to type FunctionComponent<{}>
Types of parameters __0 and props are incompatible.
Type {} is missing the following properties from type Readonly<EditBlocklistScreenProps>: navigation, route
types.d.ts(318, 5): The expected type comes from property component which is declared here on type
IntrinsicAttributes & RouteConfig<ParamListBase, BlocklistsStackScreens.EDIT_BLOCKLIST, StackNavigationState<ParamListBase>, StackNavigationOptions, StackNavigationEventMap>

Here is the code from my BlocklistStackNavigator:

import { createStackNavigator } from '@react-navigation/stack'
import { BlocklistScreen } from '../screens/Blocklists/BlocklistScreen/BlocklistScreen.tsx'
import { BlocklistsStackScreens } from './screen-lists/BlocklistsStackScreens'
import { EditPlatformBlocklistScreen } from '../screens/Blocklists/EditPlatformBlocklistScreen'
import { CreateBlocklistScreen } from '../screens/Blocklists/CreateBlocklistScreen/CreateBlocklistScreen.tsx'
import { EditBlocklistScreen } from '../screens/Blocklists/EditBlocklistScreen/EditBlocklistScreen.tsx'

const Stack = createStackNavigator()

export function BlocklistStackNavigator() {
  return (
    <Stack.Navigator initialRouteName={BlocklistsStackScreens.MAIN_BLOCKLIST}>
      <Stack.Screen
        name={BlocklistsStackScreens.MAIN_BLOCKLIST}
        component={BlocklistScreen}
        options={{ headerShown: false }}
      />

      <Stack.Screen
        name={BlocklistsStackScreens.EDIT_BLOCKLIST}
        options={{ headerShown: true }}
        component={EditBlocklistScreen}
      />

      <Stack.Screen
        name={BlocklistsStackScreens.EDIT_PLATFORM_BLOCKLIST}
        options={{ headerShown: true }}
        component={EditPlatformBlocklistScreen}
      />

      <Stack.Screen
        name={BlocklistsStackScreens.CREATE_BLOCK_LIST}
        options={{ headerShown: true }}
        component={CreateBlocklistScreen}
        initialParams={{ mode: 'create' }}
      />
    </Stack.Navigator>
  )
}

My EditBlocklistScreen :

import * as React from 'react'
import { BlocklistForm } from '../shared/BlocklistForm.tsx'
import { RouteProp } from '@react-navigation/native'
import { ScreenList } from '../../../navigators/screen-lists/screenLists.ts'
import { BlocklistsStackScreens } from '../../../navigators/screen-lists/BlocklistsStackScreens.ts'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { TabScreens } from '../../../navigators/screen-lists/TabScreens.ts'

export type EditBlocklistScreenProps = {
  navigation: NativeStackNavigationProp<ScreenList, TabScreens.BLOCKLIST>
  route?: RouteProp<ScreenList, BlocklistsStackScreens.EDIT_BLOCKLIST>
}

export function EditBlocklistScreen({
  navigation,
  route,
}: Readonly<EditBlocklistScreenProps>) {
  return (
    <BlocklistForm
      mode="edit"
      navigation={navigation}
      blocklistId={route?.params.blocklistId}
    />
  )
}

The CreateBlocklistScreen:

import * as React from 'react'
import { BlocklistForm } from '../shared/BlocklistForm.tsx'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { ScreenList } from '../../../navigators/screen-lists/screenLists.ts'
import { TabScreens } from '../../../navigators/screen-lists/TabScreens.ts'

export function CreateBlocklistScreen({
  navigation,
}: Readonly<{
  navigation: NativeStackNavigationProp<ScreenList, TabScreens.BLOCKLIST>
}>) {
  return <BlocklistForm mode="create" navigation={navigation} />
}

I've tried making the navigation and route props optional in EditBlocklistScreenProps, but it didn't solve the issue. I suspect the problem might be related to the fact that I'm using nested navigators, but I'm not sure how to resolve it.


Solution

  • You may need to provide the ScreenList in the createStackNavigator:

    import { createStackNavigator } from '@react-navigation/stack';
    
    const Stack = createStackNavigator<ScreenList>();
    

    I can't see your ScreenList but make sure to define the route parameters. e.g:

    type ScreenList = {
      EditBlocklistScreen: { userId: string }; // userId is route param
    };
    

    Checkout the documentation for more details.