具有React-Navigation的类型安全的导航处理程序

问题描述 投票:1回答:1

我的React Native应用程序的Typescript和React Navigation存在问题。我在项目中设置了以下设置,在使用以下示例时,它为我提供了很棒的帮助和自动完成功能navigation.push()

类型

import { StackNavigationProp } from '@react-navigation/stack';

export type RootStackParamList = {
    Home: undefined;
    Content: undefined;
    List: undefined;
};

export type StackNavigationProps = StackNavigationProp<RootStackParamList>;

用法

const navigation = useNavigation<StackNavigationProps>();

但是,我创建了一个导航处理程序函数,该函数带有一个被馈送到navigation.push的参数。只要参数的类型为any,它就可以正常工作。

const navigationHandler = useCallback((targetScreen) => {
    navigation.push(targetScreen);
}, [navigation]);

但是我对any类型不满意,希望targetScreen实际上只是我的RootStackParamList类型中声明的屏幕之一。我已经尝试了无数种方法来满足导航对象的push方法,但是我遇到了麻烦。

以下尝试是最成功的尝试,但仍未达到应有的效果。它确实可以在可用屏幕上为我自动补全,但是push仍然不满意。

类型:

export type NavigationScreen<T extends RootStackParamList> = {
    [K in keyof T]: K;
}[keyof T];

用法:

const navigationHandler = useCallback(
    <T extends RootStackParamList>(targetScreen: NavigationScreen<T>) => {
        navigation.push(targetScreen);
},[navigation]);

悬停错误,提示我以下内容:

(参数)targetScreen:{[T键中的K]:K; } [keyof T]的论点输入'[{[T键中的K]:K; } [keyof T]]'无法分配给'[“ Home”类型的参数| “内容” | “列表”] | [“首页” | “内容”| “列表”,未定义]”。输入'[{[T键中的K]:K; } [keyof T]]'是不可分配给类型'[“ Home” | “内容” | “列表”]'。类型'keyof T'不能分配给类型'“ Home” | “内容” | “列表”。输入'string |编号符号'不能分配给类型'“ Home” | “内容” | “列表”。类型'string'不能分配给类型'“ Home” | “内容” | “列表”。类型“ keyof T”不可分配给类型““ List””。输入'string |编号符号”不可分配给“列表”类型。类型'string'不可分配给类型'“ List”'。

如何使它工作?

typescript react-native react-navigation
1个回答
0
投票

[如果您只想将屏幕名称用于navigationHandler函数,而不是参数,则可以按照@artcorpse在他对问题的注释中建议的方式进行操作,并使用keyof RootStackParamList

const navigationHandler = useCallback(
    (targetScreen: keyof RootStackParamList) => {
        navigation.push(targetScreen);
    },
    [navigation]
);

另一方面,如果您想允许参数,则有两个选择:

选项A:通用功能

const navigationHandler = useCallback(
    <T extends keyof RootStackParamList>(
        targetScreen: T,
        targetScreenParams?: RootStackParamList[T]
    ) => {
        navigation.push(
            targetScreen as keyof RootStackParamList,
            targetScreenParams
        );
    },
    [navigation]
);

此选项的好处是,根据RootStackParamList类型中定义的相应路线检查路线参数对象的形状。例如,

type RootStackParamList = {
    Default: undefined,
    Home: {a: 'a'};
    Profile: { userId: string };
};

navigationHandler('Home', {a: 'a'}); //OK
navigationHandler('Home', {userId: 'a'}); //ERROR

选项B:反转现有类型

const navigationHandler2 = useCallback(
    (
        targetScreen: Parameters<typeof navigation.push>[0],
        targetScreenParams?: Parameters<typeof navigation.push>[1]
    ) => {
        navigation.push(targetScreen, targetScreenParams);
    },
    [navigation]
);

此选项采用您已定义的现有类型,并尝试从navigation.push方法中提取它们。不利之处在于,您不会获得上述有关路径及其相应参数对象形状的检查。

来源:

© www.soinside.com 2019 - 2024. All rights reserved.