skip to Main Content

So right now I have a routes.tsx file that holds all my types. But on the screens where I use useNavigation() I always need to create a type for it in that component. How do I properly set up a global type for my routes so I don’t have to do this?

routes.tsx

export type AuthStackParamList = {
  Landing: undefined;
  GetStarted: undefined;
  VerifyOtp: { email: string };
  PrivacyPolicy: undefined;
  TermsOfService: undefined;
};

export type AppTabParamList = {
  HomeScreen: undefined;
  FriendsScreen: undefined;
  NotificationsScreen: undefined;
  SettingsScreen: undefined;
};

export type OnboardingStackParamList = {
  UsernameScreen: undefined;
};

export type HomeTabStackParamList = {
  Home: undefined;
};

export type FriendsTabStackParamList = {
  Friends: undefined;
  SearchUsers: undefined;
};

export type SettingsTabStackParamList = {
  Settings: undefined;
  EditName: { id: string; name: string };
  EditUsername: { id: string; username: string };
  DeleteAccount: undefined;
};

AuthStack.tsx

const AuthStack = createNativeStackNavigator<AuthStackParamList>();

export function AuthStackNavigator() {
  return (
    <AuthStack.Navigator
      initialRouteName="Landing"
      }}>
      <AuthStack.Screen
        name="Landing"
        component={LandingScreen}
        options={{ headerShown: false }}
      />
      <AuthStack.Screen
        name="GetStarted"
        component={GetStartedScreen}
        options={{ headerTitle: '' }}
      />
      <AuthStack.Screen
        name="VerifyOtp"
        component={VerifyOTPScreen}
        options={{ headerShown: false, gestureEnabled: false }}
      />
      <AuthStack.Screen
        name="TermsOfService"
        component={TermsOfServiceScreen}
        options={{ headerTitle: 'Terms of Service' }}
      />
      <AuthStack.Screen
        name="PrivacyPolicy"
        component={PrivacyPolicy}
        options={{ headerTitle: 'Privacy Policy' }}
      />
    </AuthStack.Navigator>
  );
}

GetStartedScreen.tsx

This is what I want to avoid having to do whenever I need to tap into useNavigation

type GetStartedScreenNavigationProps = NativeStackNavigationProp<
  AuthStackParamList,
  'GetStarted'
>;

const GetStartedScreen = () => {
  const navigation = useNavigation<GetStartedScreenNavigationProps>();

3

Answers


  1. I think there is no way to do that.
    Because useNavigation is a hook.
    And a hook is always have to be created inside any component.
    You can’t create the hook and export it to use in any other component.

    Login or Signup to reply.
  2. According to the docs a declare global should work with useNavigation.

    Instead of manually annotating these APIs, you can specify a global
    type for your root navigator which will be used as the default type.

    To do this, you can add this snippet somewhere in your codebase:

    declare global {
      namespace ReactNavigation {
        interface RootParamList extends RootStackParamList {}
      }
    }
    

    The RootParamList interface lets React Navigation know about the params accepted by your root navigator. Here we extend the type RootStackParamList because that’s the type of params for our stack navigator at the root. The name of this type isn’t important.

    Here is a link to the chapter: https://reactnavigation.org/docs/typescript/#specifying-default-types-for-usenavigation-link-ref-etc

    Login or Signup to reply.
  3. You could create a custom hook in a separate file like this:

    export const useAuthStackNavigation = <K extends keyof AuthStackParamList>() =>
    {
      return useNavigation<NativeStackNavigationProp<AuthStackParamList, K>>(); 
    };
    

    And then in your screen:

    const GetStartedScreen = () => {
      const navigation = useAuthStackNavigation<'GetStarted'>();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search