feat: add typed navigator for better typechecking

This commit is contained in:
satyajit.happy
2019-06-11 12:01:21 +02:00
parent b2214774d6
commit 14aa95515e
5 changed files with 189 additions and 44 deletions

View File

@@ -14,7 +14,7 @@ import {
type Props = {
initialRouteName?: string;
children: React.ReactElement[];
children: React.ReactNode;
};
type Action =
@@ -28,27 +28,37 @@ export type StackNavigationProp<
ParamList extends ParamListBase,
RouteName extends keyof ParamList = string
> = NavigationProp<ParamList, RouteName> & {
/**
* Push a new screen onto the stack.
*
* @param name Name of the route for the tab.
* @param [params] Params object for the route.
*/
push<RouteName extends keyof ParamList>(
...args: ParamList[RouteName] extends void
? [RouteName]
: [RouteName, ParamList[RouteName]]
): void;
/**
* Pop a screen from the stack.
*/
pop(): void;
};
const StackRouter = {
normalize({
initial({
screens,
currentState,
partialState,
initialRouteName = Object.keys(screens)[0],
}: {
screens: { [key: string]: ScreenProps };
currentState?: InitialState | NavigationState;
partialState?: InitialState | NavigationState;
initialRouteName?: string;
}): NavigationState {
const routeNames = Object.keys(screens);
let state = currentState;
let state = partialState;
if (state === undefined) {
const index = routeNames.indexOf(initialRouteName);

View File

@@ -14,7 +14,7 @@ import {
type Props = {
initialRouteName?: string;
children: React.ReactElement[];
children: React.ReactNode;
};
type Action = {
@@ -26,6 +26,12 @@ export type TabNavigationProp<
ParamList extends ParamListBase,
RouteName extends keyof ParamList = string
> = NavigationProp<ParamList, RouteName> & {
/**
* Jump to an existing tab.
*
* @param name Name of the route for the tab.
* @param [params] Params object for the route.
*/
jumpTo<RouteName extends keyof ParamList>(
...args: ParamList[RouteName] extends void
? [RouteName]
@@ -34,18 +40,18 @@ export type TabNavigationProp<
};
const TabRouter = {
normalize({
initial({
screens,
currentState,
partialState,
initialRouteName = Object.keys(screens)[0],
}: {
screens: { [key: string]: ScreenProps };
currentState?: InitialState | NavigationState;
partialState?: InitialState | NavigationState;
initialRouteName?: string;
}): NavigationState {
const routeNames = Object.keys(screens);
let state = currentState;
let state = partialState;
if (state === undefined) {
const index = routeNames.indexOf(initialRouteName);

View File

@@ -1,7 +1,12 @@
import shortid from 'shortid';
import * as React from 'react';
import { render } from 'react-dom';
import { NavigationContainer, Screen, CompositeNavigationProp } from '../src';
import {
NavigationContainer,
Screen,
CompositeNavigationProp,
TypedNavigator,
} from '../src';
import StackNavigator, { StackNavigationProp } from './StackNavigator';
import TabNavigator, { TabNavigationProp } from './TabNavigator';
@@ -16,6 +21,16 @@ type TabParamList = {
fifth: void;
};
const Stack: TypedNavigator<StackParamList, typeof StackNavigator> = {
Navigator: StackNavigator,
Screen,
};
const Tab: TypedNavigator<TabParamList, typeof TabNavigator> = {
Navigator: TabNavigator,
Screen,
};
const First = ({
navigation,
}: {
@@ -125,23 +140,27 @@ const initialState = routes.length
function App() {
return (
<NavigationContainer initialState={initialState}>
<StackNavigator>
<Screen
<Stack.Navigator>
<Stack.Screen
name="first"
component={First}
options={{ title: 'Foo' }}
initialParams={{ author: 'Jane' }}
/>
<Screen name="second" component={Second} options={{ title: 'Bar' }} />
<Screen name="third" options={{ title: 'Baz' }}>
<Stack.Screen
name="second"
component={Second}
options={{ title: 'Bar' }}
/>
<Stack.Screen name="third" options={{ title: 'Baz' }}>
{() => (
<TabNavigator initialRouteName="fifth">
<Screen name="fourth" component={Fourth} />
<Screen name="fifth" component={Fifth} />
</TabNavigator>
<Tab.Navigator initialRouteName="fifth">
<Tab.Screen name="fourth" component={Fourth} />
<Tab.Screen name="fifth" component={Fifth} />
</Tab.Navigator>
)}
</Screen>
</StackNavigator>
</Stack.Screen>
</Stack.Navigator>
</NavigationContainer>
);
}