TypeScript中自定义Hook使用React Native useNavigation的类型问题解决
问题场景
使用@react-navigation的useNavigation创建自定义Hook时,遇到TypeScript类型不兼容问题,代码示例如下:
type RootStackParamList = { Login: { page: string } | undefined; Foo: { mode: string }; Bar: undefined; }; const useAuthNavigation = () => { const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>(); const navigate = ( page: keyof RootStackParamList, params?: RootStackParamList[keyof RootStackParamList], ) => { navigation.navigate(page, params); }; return { navigate }; }; export default useAuthNavigation;
错误信息(翻译后)
参数类型
[keyof RootStackParamList, { page: string; } | { mode: string; } | undefined]无法赋值给类型[screen: "Login"] | [screen: "Login", params: { page: string; } | undefined] | [screen: "Foo", params: { mode: string; }] | [screen: "Bar"] | [screen: "Bar", params: undefined]。
类型[keyof RootStackParamList, { page: string; } | { mode: string; } | undefined]无法赋值给类型[screen: "Login", params: { page: string; } | undefined] | [screen: "Foo", params: { mode: string; }] | [screen: "Bar", params: undefined]。
类型[keyof RootStackParamList, { page: string; } | { mode: string; } | undefined]无法赋值给类型[screen: "Bar", params: undefined]。
源类型第0位与目标类型第0位不兼容。
类型keyof RootStackParamList无法赋值给类型"Bar"。
类型"Login"无法赋值给类型"Bar"。ts(2345)
解决思路
问题核心在于原代码中page和params是独立的联合类型,TypeScript无法关联路由页面与对应参数的匹配关系,比如无法保证传入"Bar"时,params一定是undefined。
需要通过泛型约束两者的对应关系,让TypeScript能根据传入的页面自动推断合法的参数类型。
修正后的代码
import { useNavigation, NativeStackNavigationProp } from '@react-navigation/native-stack'; type RootStackParamList = { Login: { page: string } | undefined; Foo: { mode: string }; Bar: undefined; }; const useAuthNavigation = () => { const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>(); // 用泛型Screen关联页面与参数的对应类型 const navigate = <Screen extends keyof RootStackParamList>( page: Screen, params?: RootStackParamList[Screen] ) => { navigation.navigate(page, params); }; return { navigate }; }; export default useAuthNavigation;
说明
- 新增泛型
Screen,限定为RootStackParamList的键集合 - 将
params的类型约束为RootStackParamList[Screen],确保参数与当前页面严格匹配 - 调用时TypeScript会自动校验:比如
navigate("Bar")不允许传入非undefined的参数,navigate("Foo")必须传入{ mode: string }类型的参数,完全符合路由参数定义
内容的提问来源于stack exchange,提问作者jinkook Lee

