typescript - 带有 React-Navigation 的类型安全的 navigationHandler

标签 typescript react-native react-navigation

我的 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]);

将鼠标悬停在错误上,我得到以下提示:

(parameter) targetScreen: { [K in keyof T]: K; }[keyof T] Argument of type '[{ [K in keyof T]: K; }[keyof T]]' is not assignable to parameter of type '["Home" | "Content" | "List"] | ["Home" | "Content" | "List", undefined]'. Type '[{ [K in keyof T]: K; }[keyof T]]' is not assignable to type '["Home" | "Content" | "List"]'.
Type 'keyof T' is not assignable to type '"Home" | "Content" | "List"'.
Type 'string | number | symbol' is not assignable to type '"Home" | "Content" | "List"'.
Type 'string' is not assignable to type '"Home" | "Content" | "List"'.
Type 'keyof T' is not assignable to type '"List"'.
Type 'string | number | symbol' is not assignable to type '"List"'.
Type 'string' is not assignable to type '"List"'.

如何让它工作?

最佳答案

如果您只是想为您的 navigationHandler 函数使用屏幕名称而不是参数,您可以按照@artcorpse 在他对您问题的评论中的建议并使用 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 方法中提取它们。这里的缺点是您不会获得上述关于路线及其相应参数对象形状的检查。

来源:

关于typescript - 带有 React-Navigation 的类型安全的 navigationHandler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62052325/

相关文章:

typescript - 类型 'tip' 上不存在属性 'typeof @types/d3/index"'

reactjs - Typescript 输入 onchange event.target.value

javascript - 如何编写多个组件

reactjs - 使用 Flow 和 redux-navigation 验证通用 React 组件属性

react-native - undefined 不是对象(评估 'RootComponent.prototype' )

typescript - Angular2 - browser_adapter.ts 原始异常 : No provider for Location

javascript - 如何使用 Typescript 对具有后备值的解构对象进行类型检查?

react-native - 如何在水平 `FlatList` 上显示垂直分隔符?

javascript - 如何防止图像在 react native 中的 uri 重新加载时闪烁?

javascript - TypeError : e. _panGestureHandler.current.setNativeProps 不是函数