Search code examples
typescriptreact-navigationreact-navigation-v6

Type definition for react-navigation-v6 <Stack.Group>


I am not able to determine the correct type definition for a Stack group with screens (see TestStack.Group and the nested TestStack.Screen).

The navigation stack:

const TestStack = createNativeStackNavigator<TestStackParamList>();
function TestNavigator() {
  return (
    <TestStack.Navigator initialRouteName="TestScreen">
      <TestStack.Screen
        name="TestScreen"
        component={TestScreen}
        options={{ headerShown: true, title: "", headerTransparent: true }}
      />
      <TestStack.Group screenOptions={{ presentation: "modal" }}>
        <TestStack.Screen name="TestModal" component={TestModal} options={{ title: "" }} />
      </TestStack.Group>
    </TestStack.Navigator>
  );
}

As part of the root stack defined as:

export type RootStackParamList = {
  TestStack: NavigatorScreenParams<TestStackParamList> | TestScreenParams;
...
}
export type TestStackParamList = {
  TestScreen: TestScreenParams;
  TestResultScreen: TestScreenParams;
  StaticContentScreen: StaticContentParams;
};
export type TestScreenParams = {
  param1: string;
  param2: string;
};

I've tried the below (and a few other combinations..)

export type TestStackParamList = {
  TestScreen: TestScreenParams;
  TestResultScreen: TestScreenParams;
  StaticContentScreen: StaticContentParams;
  TestModal: RouteGroupConfig<TestStackGroupParamList, NativeStackNavigationOptions>;
};

export type TestStackGroupParamList = {
  TestModal: { simplified: string; type: ModalType };
};

I am getting this linter error:

Type '({ children, navigation, route, }: TestModalProps) => ReactNode' is not assignable to type 'ScreenComponentType<TestStackParamList, "TestModal"> | undefined'.

The error is clear, but I am not able to figure out the right "combination" of navigation types.


Solution

  • There's no need of special typings for Screens in Stack Groups: consider them like those without the Stack Group. So TestStackParamList could simply be like the following.

    export type TestStackParamList = {
      TestScreen: TestScreenParams;
      TestResultScreen: TestScreenParams;
      StaticContentScreen: StaticContentParams;
      TestModal: { simplified: string; type: ModalType };
    };
    

    Below there's the complete file with typings (I made some assumptions about code missing in the question). You can also check in this CodeSandbox that there's no type issues with this code.

    import React from "react";
    import {
      createNativeStackNavigator,
      NativeStackScreenProps
    } from "@react-navigation/native-stack";
    
    /* SECTION: SCREENS */
    function TestScreen() {
      // TODO: Return the actual component
      return null;
    }
    
    type TestModalProps = NativeStackScreenProps<TestStackParamList, "TestModal">;
    
    function TestModal({ route }: TestModalProps) {
      const { simplified, type } = route.params;
      // TODO: Use the route params and return the actual component
      return null;
    }
    /* END SECTION: SCREENS */
    
    /* SECTION: NAVIGATION */
    // TODO: Replace with actual modal types
    type ModalType = "type1" | "type2";
    
    export type TestScreenParams = {
      param1: string;
      param2: string;
    };
    
    export type TestModalScreenParams = {
      simplified: string;
      type: ModalType;
    };
    
    export type TestStackParamList = {
      TestScreen: TestScreenParams;
      TestResultScreen: TestScreenParams;
      StaticContentScreen: StaticContentParams;
      TestModal: TestModalScreenParams;
    };
    
    const TestStack = createNativeStackNavigator<TestStackParamList>();
    
    export function TestNavigator() {
      return (
        <TestStack.Navigator initialRouteName="TestScreen">
          <TestStack.Screen
            name="TestScreen"
            component={TestScreen}
            options={{ headerShown: true, title: "", headerTransparent: true }}
          />
          <TestStack.Group screenOptions={{ presentation: "modal" }}>
            <TestStack.Screen
              name="TestModal"
              component={TestModal}
              options={{ title: "" }}
            />
          </TestStack.Group>
        </TestStack.Navigator>
      );
    }