|
/** |
|
* This simply aggregates navigator constructors |
|
* and allows us to support more than one type of navigator. |
|
*/ |
|
const navigators = { |
|
stack: createStackNavigator, |
|
tab: createBottomTabNavigator, |
|
} as const; |
|
|
|
/** |
|
* This creates a union type of `'stack' | 'tab'`. |
|
*/ |
|
type NavigatorType = keyof typeof navigators; |
|
|
|
/** |
|
* This extracts the type of props expected by |
|
* the component returned by each of the navigator |
|
* constructors defined above in `navigators`. |
|
*/ |
|
type NavigatorProps<T extends NavigatorType> = ComponentProps< |
|
ReturnType<typeof navigators[T]>['Navigator'] |
|
>; |
|
|
|
/** |
|
* This defines a type accepting any `Navigator` or `Screen` as key |
|
* paired with the following values: |
|
* - screen: the component to render for this screen. |
|
* - options?: the navigation options to use for this screen. |
|
* - initialParams?: if the screen is present in `ScreenParameterMap`, extract the expected parameters otherwise allow nothing. |
|
*/ |
|
type ScreenMap = Partial< |
|
{ |
|
[key in Navigator | Screen]: { |
|
screen: ComponentType<any>; |
|
options?: StackNavigationOptions; |
|
initialParams?: key extends keyof ScreenParameterMap ? ScreenParameterMap[key] : never; |
|
}; |
|
} |
|
>; |
|
|
|
/** |
|
* This is how we will configure our navigator, this type is input for `makeNavigator`. |
|
* Since `screens` and `linking` are defined in the same object, we can ensure that the compiler |
|
* will warn us if entries present in `screens` are missing in `linking`. |
|
* |
|
* We can specify a custom render function and navigator level options |
|
* here while the screen level options are to be defined in `ScreenMap`. |
|
*/ |
|
interface PartialNavigatorConfiguration< |
|
TNavigatorType extends NavigatorType, |
|
TScreens extends ScreenMap |
|
> { |
|
name: Stacks; |
|
type: TNavigatorType; |
|
screens: TScreens; |
|
linking: { |
|
path?: string; |
|
initialRouteName?: Navigator | Screen; |
|
screens: Record<keyof TScreens, string | PathConfig>; |
|
}; |
|
options?: Omit<NavigatorProps<TNavigatorType>, 'children'>; |
|
render?: ComponentType<Omit<PartialNavigatorConfiguration<TNavigatorType, TScreens>, 'render'>>; |
|
} |
|
|
|
/** |
|
* This is what `makeNavigator` will return, it simply extends the shape of `PartialNavigatorConfiguration` |
|
* while overriding the type of `render` to tell the compiler it will always be present, as opposed to what |
|
* is defined in `PartialNavigatorConfiguration`. |
|
*/ |
|
interface NavigatorConfiguration< |
|
TNavigatorType extends NavigatorType, |
|
TScreens extends ScreenMap |
|
> extends Omit<PartialNavigatorConfiguration<TNavigatorType, TScreens>, 'render'> { |
|
render: ComponentType<any>; |
|
} |