You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中@react-navigation/native类型检查错误排查求助

React Native嵌套路由TypeScript类型错误解决方案

问题背景

开发React Native应用时,采用栈导航+底部标签导航的嵌套路由结构,配置TypeScript类型时遭遇类型检查错误,查阅相关文档和社区内容后未解决问题。

现有类型定义

export type RootBottomTabsParamList = {
  Dashboard: undefined;
  Categories: CategoriesStackParamList | undefined;
  Favorites: undefined;
  Cart: undefined;
  Settings: undefined;
};

export type BottomTabsNavigationProps = BottomTabNavigationProp<
  RootBottomTabsParamList,
  'Categories'
>;

export type CategoriesStackParamList = {
  CategoriesMain: undefined;
  Niche: {category: string; name: string} | undefined;
};

export type CategoriesScreenNavigationProps = StackNavigationProp<
  CategoriesStackParamList,
  'Niche'
>;

export type RootStackParamList = {
  Login: undefined;
  SignUp: undefined;
  Home: RootBottomTabsParamList | undefined;
  Product:
    | {img: string; name: string; price: string; description: sting}
    | undefined;
};

export type RootNavigationProps = StackNavigationProp<RootStackParamList>;

现有路由代码

import React from 'react';
import {BackHandler, ToastAndroid} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import Icon from 'react-native-vector-icons/MaterialIcons';
import auth from '@react-native-firebase/auth';
import firestore from '@react-native-firebase/firestore';
//screens
import {
  Cart,
  Categories,
  Dashboard,
  Favorites,
  Login,
  Product,
  Settings,
  SignUp,
  Niche,
} from './screens';
import {
  createNavigationContainerRef,
  DefaultTheme,
  DarkTheme,
} from '@react-navigation/native';
import {useAppDispatch, useAppSelector} from './redux/hook';
import {AppDispatch, RootState} from './redux/store';
import {setCart, setFavorites, setUser} from './redux/actions';
import {IProduct} from './utils/interfaces/common';
import {
  CategoriesStackParamList,
  RootBottomTabsParamList,
  RootNavigationProps,
  RootStackParamList,
} from './utils/interfaces/navigation';

export const navigationRef = createNavigationContainerRef();

export function navigate(name: string, params?: {}) {
  if (navigationRef.isReady()) {
    navigationRef.navigate(name as never, params as never);
  }
}

const Stack = createStackNavigator<
  RootStackParamList | CategoriesStackParamList
>();
const Tab = createBottomTabNavigator<RootBottomTabsParamList>();

const StackCategories = () => (
  <Stack.Navigator
    screenOptions={{
      headerShown: false,
    }}>
    <Stack.Screen name="CategoriesMain" component={Categories} />
    <Stack.Screen name="Niche" component={Niche} />
  </Stack.Navigator>
);

const bottomTabRoutes = [
  {name: 'Dashboard', component: Dashboard, iconName: 'home'},
  {name: 'Categories', component: StackCategories, iconName: 'apps'},
  {name: 'Favorites', component: Favorites, iconName: 'favorite'},
  {name: 'Cart', component: Cart, iconName: 'shopping-cart'},
  {name: 'Settings', component: Settings, iconName: 'settings'},
];

const Home = () => {
  return (
    <Tab.Navigator
      screenOptions={{
        headerShown: false,
        headerTitleStyle: {fontSize: 20, fontWeight: '600'},
        lazy: true,
      }}>
      {bottomTabRoutes.map(screen => (
        <Tab.Screen
          key={screen.name}
          name={screen.name}
          component={screen.component}
          options={{
            tabBarIcon: props => (
              <Icon {...props} name={screen.iconName} size={15} />
            ),
          }}
        />
      ))}
    </Tab.Navigator>
  );
};

export default function Routes() {
  const dispatch: AppDispatch = useAppDispatch();
  const userId = useAppSelector((state: RootState) => state.ui.user?.uid);
  const isDarkTheme = useAppSelector((state: RootState) => state.ui.dark);
  const backBtnClicked = React.useRef(0);

  React.useLayoutEffect(() => {
    async function check() {
      auth().onAuthStateChanged(onAuthStateChanged);
    }
    check();
  }, []);
 
  return (
    <NavigationContainer
      ref={navigationRef}
      theme={isDarkTheme ? DarkTheme : DefaultTheme}>
      <Stack.Navigator
        screenOptions={{
          headerShown: false,
        }}>
        <Stack.Screen name="Login" component={Login} />
        <Stack.Screen name="SignUp" component={SignUp} />
        <Stack.Screen name="Home" component={Home} />
        <Stack.Screen name="Product" component={Product} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

出现的错误

错误1:navigate函数类型不匹配

  • 错误提示:Argument of type 'string' is not assignable to parameter of type 'never'
  • 截图:
    错误截图1
    错误截图2
    错误截图3

错误2:useNavigation钩子类型错误

  • 错误提示:Property 'navigate' does not exist on type 'StackScreenProps<RootStackParamList, keyof RootStackParamList, undefined>'
  • 代码示例:
const navigation = useNavigation<StackScreenProps<RootStackParamList>>();
  • 截图:
    错误截图4

解决方案

1. 修正嵌套路由的ParamList定义

嵌套导航的参数不需要在父导航的ParamList中声明,父导航只需要标记自身屏幕的参数类型即可:

export type RootBottomTabsParamList = {
  Dashboard: undefined;
  Categories: undefined; // 移除嵌套栈的参数类型,改为undefined
  Favorites: undefined;
  Cart: undefined;
  Settings: undefined;
};

export type CategoriesStackParamList = {
  CategoriesMain: undefined;
  Niche: {category: string; name: string}; // 明确参数必传,移除|undefined(可选保留)
};

export type RootStackParamList = {
  Login: undefined;
  SignUp: undefined;
  Home: undefined; // 移除嵌套Tabs的参数类型,改为undefined
  Product: {img: string; name: string; price: string; description: string}; // 修正sting拼写错误
};

2. 分离不同的Stack导航器

不要用同一个Stack承载多个导航的联合类型,分别创建独立的Stack导航器:

// 分别创建Root栈和Categories栈,避免联合类型导致的类型推断错误
const RootStack = createStackNavigator<RootStackParamList>();
const CategoriesStack = createStackNavigator<CategoriesStackParamList>();

// 修改StackCategories组件使用专属的CategoriesStack
const StackCategories = () => (
  <CategoriesStack.Navigator
    screenOptions={{
      headerShown: false,
    }}>
    <CategoriesStack.Screen name="CategoriesMain" component={Categories} />
    <CategoriesStack.Screen name="Niche" component={Niche} />
  </CategoriesStack.Navigator>
);

3. 修正navigationRef和navigate函数的类型

给导航容器Ref指定正确的类型,避免as never强制转换:

// 指定Ref的类型为RootStack的导航容器类型
export const navigationRef = createNavigationContainerRef<RootStackParamList>();

// 给navigate函数添加泛型约束,确保参数类型匹配
export function navigate<RouteName extends keyof RootStackParamList>(
  name: RouteName,
  params?: RootStackParamList[RouteName]
) {
  if (navigationRef.isReady()) {
    navigationRef.navigate(name, params);
  }
}

4. 修正useNavigation的类型参数

使用正确的NavigationProp类型,而非StackScreenProps:

// 使用预先定义好的RootNavigationProps
const navigation = useNavigation<RootNavigationProps>();

内容的提问来源于stack exchange,提问作者KALITA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 06:20:22