BattleVlog
BattleVlog

Reputation: 683

react native typescript 'string' is not assignable to parameter of type 'never.' in useNavigation

[I keep getting the error that says 'string' is not assignable to parameter of type 'never' in react native typescript and I don't know why. Can someone help me fix this bug.

Thank you in advance.

code picture

code snippet :

const loadReport = (id: string) => {
    setPostId(id);
    navigation.navigate('Report', {postId: id});
}

I get an underline under 'Report'.

Upvotes: 68

Views: 55943

Answers (13)

Hohenheim
Hohenheim

Reputation: 1

The easiest way is, to install types/react-navigation by executing npm i @types/react-navigation

and then in your code type const navigation = useNavigation<any>();

That's how I fixed it!

Upvotes: -2

Abraham
Abraham

Reputation: 9875

Maybe would be underrated but my solution was simpler, I notified my team about the issue and:

// @ts-ignore
navigation.navigate('WHERE_TF_I_WANT');

Upvotes: 0

Tuan Dat Tran
Tuan Dat Tran

Reputation: 453

Both solutions below work for me

const navigation = useNavigation<StackNavigationProp<any>>();
or
const navigation = useNavigation<any>();

Upvotes: 2

Jerwen Pesquera
Jerwen Pesquera

Reputation: 1

import { NavigationContext } from "@react-navigation/native";


const MyComponent = () => {
  const navigation = React.useContext(NavigationContext);
  
  ...
}

Try this

Upvotes: 0

Pablo Cocciaglia
Pablo Cocciaglia

Reputation: 439

this is the correct solution of the typing you are searching for.

import React from 'react';
import {Text, View, Button} from 'react-native';
import {StackNavigationProp} from '@react-navigation/stack';
import {ParamListBase, useNavigation} from '@react-navigation/native';

enum Url {
  Page1Screen = 'Page1Screen',
  Page2Screen = 'Page2Screen',
  Page3Screen = 'Page3Screen',
}

export const Page2Screen = () => {
  const navigation = useNavigation<StackNavigationProp<ParamListBase, Url>>();
  return (
    <View>
      <Text>page2</Text>
      <Button
        title="go to page 1"
        onPress={() => navigation.navigate('Page1Screen')}
      />
      <Button
        title="go to page 3"
        onPress={() => navigation.navigate('Page3Screen')}
      />
    </View>
  );
};

Upvotes: 2

I found this solution:

const route = ["path", { data }];
navigation?.navigate(...(route as never));

Upvotes: 1

Parterdev
Parterdev

Reputation: 1211

This is a weird issue that happens in RN > 0.65. My solution:

1.- Import:

{/* Depends of your Package (Stack or NativeStack...) */}
import { StackNavigationProp } from '@react-navigation/stack';
import { useNavigation } from '@react-navigation/core';

2.- Define types

export type RootStackParamList = {
  YourScreen: { id: number } | undefined;
};

3.- Assign useNavigation hook with type StackNavigationProp.

const navigation = useNavigation<StackNavigationProp<RootStackParamList>>();

4.- Use it! (Eye: with this type you can access to navigation object)

<TouchableOpacity
   // Use this when you pass a parameter (is optional)
   onPress={() => navigation.navigate('YourScreen', {id: 5})}>
</TouchableOpacity>

5.- Remember this notes:

  • Specifying undefined means that the route doesn't have params. A union type with undefined => AnyType | undefined means that params are optional.

  • The useNavigation const have special type and this final type takes 3 generics:

  • The param list object => RootStackParamList

  • The name of the screen route => RouteName

  • The ID of the navigator (optional) => NavigatorID

Obtained from: https://reactnavigation.org/docs/typescript/#annotating-usenavigation

Upvotes: 110

TheZanke
TheZanke

Reputation: 1078

I ran into this problem as well; in my case I was starting from the Ignite boilerplate. I solved it by using:

const navigation = useNavigation<NativeStackNavigationProp<AppStackParamList>>()

Where, in my case, AppStackParamList is defined in app/navigators/AppNavigator.tsx. There can be more than one Navigator and more than one ...StackParamList; you'll wanna use the proper param list for the navigator your component is in. By passing the param list (instead of any) to NativeStackNavigationProp the type system can infer the list of route names for suggesting in navigation.navigate() as well as other things relevant to your actual screen list.

Upvotes: 3

ryanwaite28
ryanwaite28

Reputation: 2048

Just use type any when calling the hook:

const navigation = useNavigation<any>();

This isn't the recommended way of doing things but it will make the code error go away.

Upvotes: 13

Hyeonmin
Hyeonmin

Reputation: 153

You could make a maintainable navigation prop.

  1. Make a type file.
// navigation.ts
import { DrawerNavigationProp } from "@react-navigation/drawer";
import { NavigationProp } from "@react-navigation/native";
import { StackNavigationProp } from "@react-navigation/stack";

type RootStackParamList = {
  // Your custom param type belongs here.
  Login: {
    id: string;
  },
  Profile: {}, 
}

type RootDrawerParamList = {
  Shopping: {},
  Chat: {},
}

export type RootNavigationProp = NavigationProp<
 StackNavigationProp<RootStackParamList>,
 DrawerNavigationProp<RootDrawerParamList>
>;
  1. Use it.
import { useNavigation } from "@react-navigation/native";
import { RootNavigationProp } from "@somewhere/navigation";

const App = () => {
  const navigation = useNavigation<RootNavigationProp>();

  function onPress () {
    navigation.navigate("Login", {id: "userID"});
  }
}

Upvotes: 3

Daniel Alejandro
Daniel Alejandro

Reputation: 695

Simple solution is to add any to NativeStackNavigationProp type

const AppLink = ({
  text,
  screenName,
}: Link) => {

  // pass any to overload 
  const navigation = useNavigation<NativeStackNavigationProp<any>>();

  const handleNavigation = () => {
    navigation.navigate(screenName);
  };  
  
  return (
    <TouchableOpacity onPress={handleNavigation}>
      <Text>{text}</Text>
    </TouchableOpacity>
  );
};

export default AppLink;

Upvotes: 25

lee_mcmullen
lee_mcmullen

Reputation: 3177

I too was getting the following ts error when not annotating useNavigation and trying to call navigation.navigate('OtherJazzyScreen)`:

Argument of type 'string' is not assignable to parameter of type '{ key: string; params?: undefined; merge?: boolean | undefined; } | { name: never; key?: string | undefined; params: never; merge?: boolean | undefined; }'

The OP doesn't specify which version of react-navigation they're using but you can fix this globally in React Navigation 6 which means you then don't have to annotate useNavigation directly but you still get autocomplete and type checking.

Taken from the react-navigation blog in August 2021 (https://reactnavigation.org/blog/2021/08/14/react-navigation-6.0/#better-type-safety):

In React Navigation 6, you don’t need to annotate useNavigation to get autocompletion and type checking. This is possible by defining a type for the screens globally using declaration merging:

declare global {   
  namespace ReactNavigation {
    interface RootParamList {
      Home: undefined;
      Profile: { userId: string };
      NotFound: undefined;
    }   
  } 
 } 

You can read more about it in our TypeScript docs.

Another example from the React Navigation 6 docs, if you already have your params declared elsewhere:

// E.g. RootStackParamList.ts
export type RootStackParamList = {
  Home: undefined;
  Profile: { userId: string };
  NotFound: undefined;
};

// E.g. App.tsx
import { RootStackParamList } from 'path/to/RootStackParamList';
declare global {
  namespace ReactNavigation {
    interface RootParamList extends RootStackParamList {}
  }
}

Upvotes: 13

The only solution I found is to apply the type never on the string name.

const goToContent = () => {
    navigate("Content" as never, {} as never);
};

I'm not sure it's the best solution but it's work.

Upvotes: 55

Related Questions