Quantcast
Channel: Active questions tagged react-native+typescript - Stack Overflow
Viewing all articles
Browse latest Browse all 6211

React Navigation 5 type error when navigating between stacks

$
0
0

I'm getting some TypeScript errors when using react-navigation 5. I'm sure this is something I am doing wrong with regards to how I am typing things / structuring the app but I'm not sure what.

I was following these guides on the documentation as a starting point:

https://reactnavigation.org/docs/en/tab-based-navigation.html#a-stack-navigator-for-each-tabhttps://reactnavigation.org/docs/en/typescript.html

I want to have an app structure like this:

  • Root Tab Navigator
    • Home Stack
      • Home Page
      • News Detail Page
    • Settings Stack
      • Settings Page

Everything is working fine when it runs but I'm getting some type of errors when trying to navigate from a page inside one stack to a page in another stack e.g navigating from News Detail Page to Settings page.

This is the code I currently have.

import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { createStackNavigator, StackNavigationProp } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

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

enum AppRoute {
    // Home Stack
    HOME = 'HOME',
    NEWS_DETAILS = 'NEWS_DETAILS',

    // Settings Stack
    SETTINGS = 'SETTINGS',
}

type HomeStackParamList = {
    [AppRoute.HOME]: undefined;
    [AppRoute.NEWS_DETAILS]: {
        id: number;
    };
}

type SettingsStackParamList = {
    [AppRoute.SETTINGS]: undefined;
}


type HomeProps = {
    navigation: StackNavigationProp<
        HomeStackParamList,
        AppRoute.HOME
    >;
    route: RouteProp<HomeStackParamList, AppRoute.HOME>;
}

type NewsDetailsProps = {
    navigation: StackNavigationProp<
        HomeStackParamList,
        AppRoute.NEWS_DETAILS
    >;
    route: RouteProp<HomeStackParamList, AppRoute.NEWS_DETAILS>;
}

type SettingsProps = {
    navigation: StackNavigationProp<
        SettingsStackParamList,
        AppRoute.SETTINGS
    >;
    route: RouteProp<SettingsStackParamList, AppRoute.SETTINGS>;
}


// ----------------------------------------------------------------------------

function HomeScreen(props: HomeProps) {
    const { navigation } = props;

    return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Home screen</Text>
            <Button
                title="Go to Details"
                onPress={() => navigation.navigate(AppRoute.NEWS_DETAILS, { id: 1 })}
            />
            <Button
                title="Go to Settings"
                onPress={() => navigation.navigate(AppRoute.SETTINGS)}
            />
        </View>
    );
}


function DetailsScreen(props: NewsDetailsProps) {
    return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Details! {props.route.params.id}</Text>
        </View>
    );
}


function SettingsScreen(props: SettingsProps) {
    const { navigation } = props;

    return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Settings screen</Text>
            <Button
                title="Go to Home -> Details"
                onPress={() => navigation.navigate(AppRoute.NEWS_DETAILS, { id: 2 })}
            />
        </View>
    );
}

const HomeStack = createStackNavigator<HomeStackParamList>();

function HomeStackScreen() {
    return (
        <HomeStack.Navigator>
            <HomeStack.Screen name={AppRoute.HOME} component={HomeScreen} />
            <HomeStack.Screen name={AppRoute.NEWS_DETAILS} component={DetailsScreen} />
        </HomeStack.Navigator>
    );
}


const SettingsStack = createStackNavigator<SettingsStackParamList>();

function SettingsStackScreen() {
    return (
        <SettingsStack.Navigator>
            <SettingsStack.Screen name={AppRoute.SETTINGS} component={SettingsScreen} />
        </SettingsStack.Navigator>
    );
}


const Tab = createBottomTabNavigator();

type TabNavigatorProps = React.ComponentProps<typeof Tab.Navigator>;

export const AppNavigator = (props: Partial<TabNavigatorProps>): React.ReactElement => {
    return (
        <Tab.Navigator>
            <Tab.Screen name="Home" component={HomeStackScreen} />
            <Tab.Screen name="Settings" component={SettingsStackScreen} />
        </Tab.Navigator>
    );
}

This is the error I'm getting:

No overload matches this call.
  Argument of type '[AppRoute.SETTINGS]' is not assignable to parameter of type '[AppRoute.HOME | AppRoute.NEWS_DETAILS] | [AppRoute.HOME | AppRoute.NEWS_DETAILS, { id: number; }]'.
    Type '[AppRoute.SETTINGS]' is not assignable to type '[AppRoute.HOME | AppRoute.NEWS_DETAILS]'.
      Type 'AppRoute.SETTINGS' is not assignable to type 'AppRoute.HOME | AppRoute.NEWS_DETAILS'.
  Overload 2 of 2, '(route: { key: string; params?: { id: number; }; } | { name: AppRoute.HOME | AppRoute.NEWS_DETAILS; key?: string; params: { id: number; }; }): void', gave the following error.
    Argument of type 'AppRoute.SETTINGS' is not assignable to parameter of type '{ key: string; params?: { id: number; }; } | { name: AppRoute.HOME | AppRoute.NEWS_DETAILS; key?: string; params: { id: number; }; }'.ts(2769)

I think I understand why this is happening, it's because HomeStackParamList doesn't have the settings route defined in it. Should I create a union type of every stacks page params and use that everywhere so I don't have this error or is there a better way to structure this?

I'm thinking I could possibly just create a union type of all the param lists like this but I'm not sure if that is the correct way or not? Something like this:

type HomeStackParamList = {
    [AppRoute.HOME]: undefined;
    [AppRoute.HOME_DETAILS]: {
        id: number;
    };
}

type SettingsStackParamList = {
    [AppRoute.SETTINGS]: undefined;
}

type AppStackParamList = HomeStackParamList & SettingsStackParamList;

type HomeProps = {
    navigation: StackNavigationProp<
        AppStackParamList,
        AppRoute.HOME
    >;
    route: RouteProp<AppStackParamList, AppRoute.HOME>;
}

type DetailsProps = {
    navigation: StackNavigationProp<
        AppStackParamList,
        AppRoute.HOME_DETAILS
    >;
    route: RouteProp<AppStackParamList, AppRoute.HOME_DETAILS>;
}

type SettingsProps = {
    navigation: StackNavigationProp<
        AppStackParamList,
        AppRoute.SETTINGS
    >;
    route: RouteProp<AppStackParamList, AppRoute.SETTINGS>;
}

Any help advice to point me in the right direction would be greatly appreciated, thank you


Viewing all articles
Browse latest Browse all 6211

Trending Articles