I’m trying to follow this guide for type checking with TypeScript and React Navigation but I’m getting this error anytime I try to navigate to a screen in another tab:
Argument of type '[AppRoutes.LIBRARY_TAB, { screen: AppRoutes; params: { title: string; }; }]' is not assignable to parameter of type '[screen: AppRoutes.LIBRARY_TAB] | [screen: AppRoutes.LIBRARY_TAB, params: LibraryStackParamList]'.
Type '[AppRoutes.LIBRARY_TAB, { screen: AppRoutes; params: { title: string; }; }]' is not assignable to type '[screen: AppRoutes.LIBRARY_TAB, params: LibraryStackParamList]'.
Type at position 1 in source is not compatible with type at position 1 in target.
Object literal may only specify known properties, and 'screen' does not exist in type 'LibraryStackParamList'.ts(2345)
Here are my component props:
type ConversationScreenProps = CompositeScreenProps<
StackScreenProps<HomeStackParamList, AppRoutes.CONVERSATION>,
BottomTabScreenProps<MainTabsParamList, AppRoutes.HOME_TAB>
>;
And I’m navigating to the screen like this:
navigation.navigate(AppRoutes.LIBRARY_TAB, {
screen: AppRoutes.MEDITATION_PLAYER, // This is where the error shows up
params: {
title: suggestedMeditation,
},
});
My stack/tabs nesting structure is like this:
- MainStack (NativeStackNavigator)
- MainTabs (BottomTabNavigator)
- HomeStack (StackNavigator, if I change this one to a NativeStackNavigator then I get an error about some gesture handler)
- ConversationScreen
- ...
- LibraryStack (StackNavigator)
- LibraryHomeScreen
- MeditationsScreen
- MeditationPlayerScreen
- ...
- PaywallStack (NativeStackNavigator)
- AuthScreen
- PlansScreen
- ...
Here are some of the types for my tabs and stacks:
export type MainStackParamList = {
[AppRoutes.MAIN_TABS]: undefined;
[AppRoutes.AUTH]: {
justLogIn?: boolean;
};
[AppRoutes.PAYWALL_STACK]: undefined;
};
export type MainTabsParamList = {
[AppRoutes.HOME_TAB]: HomeStackParamList;
[AppRoutes.LIBRARY_TAB]: LibraryStackParamList;
...
};
export type LibraryStackParamList = {
[AppRoutes.LIBRARY_HOME]: undefined;
[AppRoutes.MEDITATIONS]: undefined;
[AppRoutes.MEDITATION_PLAYER]: {
title: string;
};
...
};
export type ConversationScreenParamList = {
conversationId?: string;
journalEntryText?: string;
myMapSection?: string;
myMapSectionResponse?: string;
newConvoTopic?: string;
};
export type HomeStackParamList = {
[AppRoutes.HOME_SCREEN]: undefined;
[AppRoutes.CONVERSATION]: ConversationScreenParamList | undefined;
...
};
Here’s an even more detailed view of my tabs/stacks in case that helps:
const PaywallStackNav = createNativeStackNavigator<PaywallStackParamList>();
const PaywallStack = () => (
<PaywallStackNav.Navigator screenOptions={{ headerShown: false }}>
<PaywallStackNav.Screen name={AppRoutes.AUTH} component={Auth} />
<PaywallStackNav.Screen name={AppRoutes.PLANS} component={PlansScreen} />
</PaywallStackNav.Navigator>
);
const MainStack = createNativeStackNavigator<MainStackParamList>();
const Main = () => (
<MainStack.Navigator screenOptions={{ headerShown: false }}>
<MainStack.Screen name={AppRoutes.MAIN_TABS} component={MainTabs} />
<MainStack.Screen
name={AppRoutes.PAYWALL_STACK}
component={PaywallStack}
options={{ presentation: "modal" }}
/>
</MainStack.Navigator>
);
const Tabs = createBottomTabNavigator<MainTabsParamList>();
const LibraryStack = createStackNavigator<LibraryStackParamList>();
const HomeStack = createStackNavigator<HomeStackParamList>();
const LibraryTab = () => (
<LibraryStack.Navigator initialRouteName={AppRoutes.LIBRARY_HOME}>
<LibraryStack.Screen
name={AppRoutes.LIBRARY_HOME}
component={LibraryHomeScreen}
options={{ title: "Library" }}
/>
<LibraryStack.Screen
name={AppRoutes.MEDITATION_PLAYER}
component={MeditationPlayerScreen}
/>
</LibraryStack.Navigator>
);
const HomeTab = () => (
<HomeStack.Navigator initialRouteName={AppRoutes.HOME_SCREEN}>
<HomeStack.Screen name={AppRoutes.HOME_SCREEN} component={Home} />
<HomeStack.Screen name={AppRoutes.CONVERSATION} component={Conversation} />
</HomeStack.Navigator>
);
const MainTabs = () => (
<Tabs.Navigator initialRouteName={AppRoutes.HOME_TAB}>
<Tabs.Screen
name={AppRoutes.LIBRARY_TAB}
component={LibraryTab}
options={{
tabBarLabel: "Library",
tabBarIcon: ({ focused }) => <TabBarIcon focused={focused} icon="library-outline" />
}}
/>
<Tabs.Screen
name={AppRoutes.HOME_TAB}
component={HomeTab}
options={{
tabBarLabel: AppRoutes.HOME_SCREEN,
tabBarIcon: ({ focused }) => <TabBarIcon focused={focused} icon="home-outline" />
}}
/>
</Tabs.Navigator>
);
I’m pretty sure I need to use the composite navigator (since I’m navigating across tabs/stacks), but it seems like I’m doing it wrong? Any idea what I need to change so it’s not throwing a type error?
Let me know if I should include any other specific info or code (e.g. where I’m declaring my stacks/tabs).