Skip to content

Commit

Permalink
feat: makes NavigationContainerRef.getCurrentRoute type safe
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasloisp committed Aug 5, 2023
1 parent c43208f commit 06bd61f
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 1 deletion.
34 changes: 34 additions & 0 deletions example/__typechecks__/common.check.tsx
Expand Up @@ -8,8 +8,10 @@ import type {
} from '@react-navigation/drawer';
import type {
CompositeScreenProps,
NavigationContainerRef,
NavigationHelpers,
NavigatorScreenParams,
Route,
} from '@react-navigation/native';
import type { StackNavigationOptions } from '@react-navigation/stack';
import {
Expand Down Expand Up @@ -350,3 +352,35 @@ export const ThirdScreen = ({
// @ts-expect-error
if (ScreenName === 'NoParams') navigation.navigate(ScreenName, { id: '123' });
};

/**
* Check for errors on getCurrentRoute
*/
declare const navigationRef: NavigationContainerRef<RootStackParamList>;
const route = navigationRef.getCurrentRoute()!;

switch (route.name) {
case 'PostDetails':
expectTypeOf(route.params).toMatchTypeOf<{
id: string;
section?: string;
}>();
break;
case 'Login':
expectTypeOf(route.params).toMatchTypeOf<undefined>();
break;
case 'Account':
expectTypeOf(route.params).toMatchTypeOf<undefined>();
break;
case 'Popular':
expectTypeOf(route.params).toMatchTypeOf<{
filter: 'day' | 'week' | 'month';
}>();
break;
}

declare const navigationRefUntyped: NavigationContainerRef<string>;

expectTypeOf(navigationRefUntyped.getCurrentRoute()).toMatchTypeOf<
Route<string> | undefined
>();
26 changes: 26 additions & 0 deletions example/__typechecks__/static.check.tsx
@@ -1,5 +1,6 @@
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import type {
NavigationContainerRef,
NavigationProp,
StaticParamList,
StaticScreenProps,
Expand Down Expand Up @@ -196,3 +197,28 @@ createStackNavigator({});
createStackNavigator({
screens: {},
});

/**
* Check for errors on getCurrentRoute
*/
declare const navigationRef: NavigationContainerRef<ParamList>;
const route = navigationRef.getCurrentRoute()!;

switch (route.name) {
case 'Profile':
expectTypeOf(route.params).toMatchTypeOf<{
user: string;
}>();
break;
case 'Settings':
expectTypeOf(route.params).toMatchTypeOf<undefined>();
break;
case 'Login':
expectTypeOf(route.params).toMatchTypeOf<undefined>();
break;
case 'Register':
expectTypeOf(route.params).toMatchTypeOf<{
method: 'email' | 'social';
}>();
break;
}
14 changes: 13 additions & 1 deletion packages/core/src/types.tsx
Expand Up @@ -648,6 +648,18 @@ export type NavigationContainerEventMap = {
};
};

type ParamListRoute<ParamList extends ParamListBase> = {
[RouteName in keyof ParamList]: ParamList[RouteName] extends NavigatorScreenParams<
infer T extends ParamListBase
>
? ParamListRoute<T>
: Route<Extract<RouteName, string>, ParamList[RouteName]>;
}[keyof ParamList];

type MaybeParamListRoute<ParamList extends {}> = ParamList extends ParamListBase
? ParamListRoute<ParamList>
: Route<string>;

export type NavigationContainerRef<ParamList extends {}> =
NavigationHelpers<ParamList> &
EventConsumer<NavigationContainerEventMap> & {
Expand All @@ -664,7 +676,7 @@ export type NavigationContainerRef<ParamList extends {}> =
/**
* Get the currently focused navigation route.
*/
getCurrentRoute(): Route<string> | undefined;
getCurrentRoute(): MaybeParamListRoute<ParamList> | undefined;
/**
* Get the currently focused route's options.
*/
Expand Down

0 comments on commit 06bd61f

Please sign in to comment.