I am new to React and TypeScript and I created an app with Expo Go that contains the React Bottom Tab Navigator (https://reactnavigation.org/docs/bottom-tab-navigator/). My problem is that the example does not define the types for the {navigation}
parameter and I would like to solve this.
Note: it works without defining the type, but I would like to learn and understand how to fix it...
I have a Navigation.tsx
containing my root stack and the tabs (I hope I limited it to the relevant parts)
const Stack = createNativeStackNavigator();
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList { }
}
}
type RootStackParamList = {
Tabs: NavigatorScreenParams<RootTabParamList> | undefined;
Modal: undefined;
NotFound: undefined;
};
export type RootStackScreenProps<Screen extends keyof RootStackParamList> = NativeStackScreenProps<
RootStackParamList,
Screen
>;
const BottomTab = createBottomTabNavigator<RootTabParamList>();
type RootTabParamList = {
About: undefined;
Test: undefined;
};
export type RootTabScreenProps<Screen extends keyof RootTabParamList> = CompositeScreenProps<
BottomTabScreenProps<RootTabParamList, Screen>,
NativeStackScreenProps<RootStackParamList>
>;
export default function Navigation({ colorScheme }: { colorScheme: ColorSchemeName }) {
return (
<NavigationContainer
linking={LinkingConfiguration}
theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}
>
<Stack.Navigator>
<Stack.Screen name="Tabs" component={BottomTabNavigator} options={{ headerShown: false }}/>
// (!) Problem line
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }}/>
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="Modal" component={ModalScreen} />
</Stack.Group>
</Stack.Navigator>
</NavigationContainer>
);
}
I found out which is the right type for the {navigation}
in one of the tabs, e.g. About.tsx
:
import React from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
import { Text, View } from '../ui/Components';
import { RootTabScreenProps } from '../ui/Navigation';
export default function About({ navigation }: RootTabScreenProps<'About'>) {
return (
<View style={styles.container}>
<Text style={styles.title}>About</Text>
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
<Text>/screens/About.tsx</Text>
<TouchableOpacity onPress={() => navigation.replace('Tabs')}>
<Text>Go to home screen!</Text>
</TouchableOpacity>
</View>
);
}
But I can't find the right type for the {navigation}
in the root components (no tabs), like NotFound.tsx
:
import React from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
import { Text, View } from '../ui/Components';
// (!) Problem line
export default function NotFoundScreen({ navigation }: ?????) {
return (
<View style={styles.container}>
<Text style={styles.title}>This screen doesn't exist.</Text>
<TouchableOpacity onPress={() => navigation.replace('Tabs')} style={styles.link}>
<Text style={styles.linkText}>Go to home screen!</Text>
</TouchableOpacity>
</View>
);
}
Without the type, I (of course) get an error in NotFound.tsx
, that
Binding element 'navigation' implicitly has an 'any' type.
I tried RootStackScreenProps<'NotFound'>
, which will let the error above disappear, but instead I get an error in Navigation.tsx
on line <Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }}/>
:
Type '({ navigation }: RootStackScreenProps<"NotFound">) => Element' is not assignable to type 'ScreenComponentType<ParamListBase, "NotFound"> | undefined'.
Type '({ navigation }: RootStackScreenProps<"NotFound">) => Element' is not assignable to type 'FunctionComponent<{}>'.
Types of parameters '__0' and 'props' are incompatible.
Type '{}' is missing the following properties from type 'RootStackScreenProps<"NotFound">': navigation, route
So... What is the right type to use here?
react navigation was written in typescript, so any type you would need relating to it probably exists. Here they cover typing a Stack Navigator, and its same premises for a bottom tab navigator. You just need to export RootStackParamList
and import NativeStackScreenProps
in your NotFound.tsx
:
import React from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
import { RootStackParamList } from '../ui/Navigation';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import { Text, View } from '../ui/Components';
type Props = NativeStackScreenProps<RootStackParamList>; // don't use <Screen> here
export default function NotFoundScreen({ navigation }: Props) {
return (
<View style={styles.container}>
<Text style={styles.title}>This screen doesn't exist.</Text>
<TouchableOpacity onPress={() => navigation.replace('Tabs')} style={styles.link}>
<Text style={styles.linkText}>Go to home screen!</Text>
</TouchableOpacity>
</View>
);
}