英文:
React Native bottom tab navigator element is not assignable
问题
The correct type to use for the {navigation} parameter in the NotFound.tsx component is RootStackScreenProps<'NotFound'>.
So your NotFound.tsx component should look like this:
import React from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
import { Text, View } from '../ui/Components';
import { RootStackScreenProps } from '../ui/Navigation';
export default function NotFoundScreen({ navigation }: RootStackScreenProps<'NotFound'>) {
  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>
  );
}
This should resolve the type error in NotFound.tsx.
英文:
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'.<br/>
>  Type '({ navigation }: RootStackScreenProps<"NotFound">) => Element' is not assignable to type 'FunctionComponent<{}>'.<br/>
>    Types of parameters '__0' and 'props' are incompatible.<br/>
>      Type '{}' is missing the following properties from type 'RootStackScreenProps<"NotFound">': navigation, route
So... What is the right type to use here?
答案1
得分: 1
React Navigation是使用TypeScript编写的,因此与它相关的任何类型可能都已存在。在这里,它们涵盖了如何为堆栈导航器进行类型检查,底部选项卡导航器的原理也相同。您只需在您的 NotFound.tsx 中导出 RootStackParamList 并导入 NativeStackScreenProps:
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>; // 不要在这里使用 <Screen>
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>
  );
}
英文:
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>
  );
}
答案2
得分: 0
感谢 @phantomspooks 的帮助和他的回答(https://stackoverflow.com/a/76248413/4090157),我现在对类型有了更好的理解。
最终,我通过进行以下更改成功解决了我的问题:
- 在 
Navigation.tsx中从export type RootStackScreenProps中删除<Screen> 
export type RootStackScreenProps = NativeStackScreenProps<
    RootStackParamList
>;
- 在 
NotFound.tsx中使用该类型 
export default function NotFoundScreen({ navigation }: RootStackScreenProps) {
    ...
}
英文:
Thanks to the help of @phantomspooks and his answer (https://stackoverflow.com/a/76248413/4090157), I think I now understand the types a bit better.
I was finally able to resolve my problem by making the following changes:
- Remove 
<Screen>fromexport type RootStackScreenPropsinNavigation.tsx 
export type RootStackScreenProps = NativeStackScreenProps<
	RootStackParamList
>;
- Use that type in 
NotFound.tsx 
export default function NotFoundScreen({ navigation }: RootStackScreenProps) {
    ...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论