ค้นหาเว็บไซต์

typescript - ข้อผิดพลาดชนิดของ React Navigation 5 เมื่อสลับไปมาระหว่างสแตก


ฉันกำลังเจอข้อผิดพลาดของ TypeScript บ้างเมื่อใช้ react-navigation 5 ฉันมั่นใจว่านี่เป็นความผิดพลาดของฉันเกี่ยวกับวิธีการพิมพ์สิ่งต่าง ๆ/การจัดโครงสร้างแอป แต่ฉันไม่แน่ใจว่าคืออะไร

ฉันกำลังติดตามคู่มือเหล่านี้ในเอกสารเป็นจุดเริ่มต้น:

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

ฉันต้องการมีโครงสร้างแอปแบบนี้:

  • ตัวนำทางแท็บราก

    • โฮมสแตก

      • หน้าแรก
      • สแต็กหน้าหลัก
      • หน้าหลัก

      • หน้ารายละเอียดข่าว
    • สแต็กการตั้งค่า

      • หน้าการตั้งค่า

ทุกอย่างทำงานได้ดีเมื่อรัน แต่ฉันพบข้อผิดพลาดบางประเภทเมื่อพยายามไปยังหน้าจากหน้าในสแตกหนึ่งไปยังหน้าในสแตกอื่น เช่น การไปยัง หน้ารายละเอียดข่าว ไปยัง หน้าการตั้งค่า

นี่คือโค้ดที่ฉันมีอยู่ตอนนี้

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>
    );
}

นี่คือข้อผิดพลาดที่ฉันได้รับ:

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)

ฉันคิดว่าฉันเข้าใจว่าทำไมสิ่งนี้ถึงเกิดขึ้น มันเป็นเพราะ HomeStackParamList ไม่มีเส้นทาง settings กำหนดอยู่ในนั้น ฉันควรสร้าง union type ของพารามิเตอร์ของทุกหน้าของสแต็กแล้วใช้มันทุกที่เพื่อที่ฉันจะได้ไม่พบข้อผิดพลาดนี้ หรือมีวิธีที่ดีกว่าในการจัดโครงสร้างนี้ไหม?

ฉันกำลังคิดว่าฉันอาจจะสร้างชนิด union ของรายการพารามิเตอร์ทั้งหมดแบบนี้ แต่ฉันไม่แน่ใจว่านี่เป็นวิธีที่ถูกต้องหรือเปล่า? อะไรประมาณนี้:

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>;
}

คำแนะนำหรือความช่วยเหลือใด ๆ ที่สามารถชี้ทางให้ฉันไปในทิศทางที่ถูกต้องจะเป็นที่ชื่นชมอย่างมาก ขอบคุณ

คำตอบ #1

ใช่ การรวมรายการพารามิเตอร์สำหรับกรณีการใช้นี้ก็โอเค