I’m having some diffuculties specifing the parameters for a function (onError) that receive the return of a useNavigation())
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs'
import { CompositeScreenProps, NavigatorScreenParams, useNavigation } from '@react-navigation/native'
import { NativeStackNavigationProp, NativeStackScreenProps } from '@react-navigation/native-stack'
import { AxiosError } from 'axios'
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
export type RootStackParamList = {
SignIn: undefined
ResetPassword: { email: string }
Tabs: NavigatorScreenParams<TabsParamList> | undefined
Modal: undefined
Error: { error: AxiosError | string } | undefined
}
export type TabsParamList = {
Overview: NavigatorScreenParams<OverviewParamList> | undefined
Allocation: undefined
Menu: NavigatorScreenParams<MenuParamList> | undefined
}
export type OverviewParamList = {
OverviewRoot: undefined
Deposit: undefined
}
export type MenuParamList = {
MenuRoot: undefined
UserProfile: undefined
// other settings
}
export type RouteName = keyof RootStackParamList | keyof OverviewParamList | keyof TabsParamList | keyof MenuParamList
export const routeTypeGuard = (route: RouteName) => route as keyof RootStackParamList
export type RootStackScreenProps<Screen extends keyof RootStackParamList> = NativeStackScreenProps<
RootStackParamList,
Screen
>
export type RootTabScreenProps<Screen extends keyof TabsParamList> = CompositeScreenProps<
BottomTabScreenProps<TabsParamList, Screen>,
NativeStackScreenProps<RootStackParamList>
>
export function useErrorHandling() {
const navigation = useNavigation()
// navigation.replace() // this throws a type error - which seems right
return { onError: (error: unknown) => onError(navigation, error) } // how to avoid this to throw an error ??
}
export function onError(
nav: ReturnType<typeof useNavigation<NativeStackNavigationProp<RootStackParamList>>>,
error: unknown
) {
// nav.replace // does not throw type error, but experienced it to make the app crash because nav.replace was undefined
nav.navigate('Error', { error: error instanceof Error ? error.message : 'Unknow error' })
}
Advertisement
Answer
I have not personally worked with @react-navigation, so I’m going by the types only, but it looks like useNavigation, when called without type parameters, defaults to ReactNavigation.RootParamList which doesn’t match your RootStackParamList. The non-extistent replace method comes from the use of NativeStackNavigationProp rather than the default NavigationProp.
If you specify type parameters RootStackParamList and keyof RootStackParamList for useNavigation and replace NativeStackNavigationProp with NavigationProp (from '@react-navigation/core'), it type checks correctly:
export function useErrorHandling() {
const navigation =
useNavigation<NavigationProp<RootStackParamList, keyof RootStackParamList>>()
// navigation.replace() // Error: Property 'replace' does not exist on type ..
return { onError: (error: unknown) => onError(navigation, error) }
}
Additionally, you could simplify the nav argument type for onError a little bit by using NavigationProp<RootStackParamList, keyof RootStackParamList> instead of the ReturnType application:
export function onError(
nav: NavigationProp<RootStackParamList, keyof RootStackParamList>,
error: unknown
) {
nav.navigate('Error', { error: error instanceof Error ? error.message : 'Unknow error' })
}