I am working with expo and React Native, trying to push props to other screens using navigation. The code compiles and pushes the props, but I get this error when passing the props as a second argument to the navigation.navigate() function:
Argument of type ‘[never, { email: string; password: string; }]’ is not assignable to parameter of type ‘never’.
I also get this error when trying to navigate to a screen without passing props:
Argument of type ‘string’ is not assignable to parameter of type ‘{ key: string; params?: undefined; merge?: boolean | undefined; } | { name: "SignUp"; key?: string | undefined; params: undefined; merge?: boolean | undefined; } | { key: string; params?: { email: string; password: string; } | undefined; merge?: boolean | undefined; } | … 10 more … | { …; }’.ts(2345)
It goes away when I add ‘as never’.
This is where I call the function in my SignUp.tsx screen:
import { RootStackParamList } from "../../App";
import { NativeStackScreenProps } from "@react-navigation/native-stack";
type propsType = NativeStackScreenProps<RootStackParamList, 'SignUp'>;
const SignUp = (props: propsType) => {
const {navigation} = props;
.......
return(
...
<MainButton
canGoBack
style={tw`h-20 justify-center mt-3 mx-auto`}
text={"Sign up"}
targetPage="Characteristics"
onPress={() => navigation.navigate("Characteristics" )}
navigationData={{ email: formInput.email, password: formInput.password }} />)
This is the App.tsx where I have the RootStackParamList type and also the Stack Navigator:
export type RootStackParamList = {
Login: undefined;
SignUp: undefined;
ProfileSetup: undefined;
ProfileSetupDetails: undefined;
IdealMatch: undefined;
Characteristics: {
email: string,
password: string;
};
Profile: undefined;
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export type Props = NativeStackScreenProps<RootStackParamList, 'Characteristics'>;
const App: React.FC<RootStackParamList> = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Login" component={Login}
options={{ headerShown: false }}/>
<Stack.Screen name="SignUp" component={SignUp}
options={{ headerShown: false }}/>
<Stack.Screen name="ProfileSetup" component={ProfileSetup}
options={{ headerShown: false }}/>
<Stack.Screen name="ProfileSetupDetails" component={ProfileSetupDetails}
options={{ headerShown: false }}/>
<Stack.Screen name="IdealMatch" component={IdealMatch}
options={{ headerShown: false }}/>
<Stack.Screen name="Characteristics" component={Characteristics}
options={{ headerShown: false }}
/>
<Stack.Screen name="Profile" component={Profile}
options={{ headerShown: false }}/>
</Stack.Navigator>
</NavigationContainer>
);
}
I need suggestions. I am relatively new to React Native and react navigation.
Creating a route const with the path name and the data I’m pushing and passing it to the navigate seemed to fix it, but I don’t know if its ok to leave it like this:
const route = ["Characteristics", { email: formInput.email, password: formInput: password}];
navigation.navigate(...(route as never));
2
Answers
Fixed it by creating a navigation constant and removing the props: propsType arg from my SignUp screen:
I still wonder if i have to create a new navigation constant on each screen of the stack?
I don’t know the react-navigation package in particular, but regarding your
as never
cast, the issue is that your route is an array of the union type(string | params)[]
, rather than the tuple type[string, params]
. When you spread an array into navigate, it won’t accept anything but astring
in the first parameter, but spreading your currentroute
tells it that it might receive either astring
ortypeof params
.Rather than this:
Add
as const
to your definition, which tells Typescript "this is a tuple type":See this playground link for a demonstration of the difference.
The
as never
cast tells Typescript to ignore any inferred type data, and to just treat the given variable asnever
. It punches a hole in the typechecking, and should be done only very rarely, and when you specifically know that type overrides are appropriate.