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