<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Ashoat Tevosyan on Medium]]></title>
        <description><![CDATA[Stories by Ashoat Tevosyan on Medium]]></description>
        <link>https://medium.com/@ashoat_t?source=rss-b13b78e1d26a------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*8qfWwe5yDmKFHGguCAjwYQ.png</url>
            <title>Stories by Ashoat Tevosyan on Medium</title>
            <link>https://medium.com/@ashoat_t?source=rss-b13b78e1d26a------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 23 Jun 2026 13:06:06 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@ashoat_t/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Flow libdefs for React Navigation 5]]></title>
            <link>https://medium.com/@ashoat_t/flow-libdefs-for-react-navigation-5-7dcf1f9da8b7?source=rss-b13b78e1d26a------2</link>
            <guid isPermaLink="false">https://medium.com/p/7dcf1f9da8b7</guid>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[react-navigation]]></category>
            <category><![CDATA[flowtype]]></category>
            <category><![CDATA[react-navigation-5]]></category>
            <dc:creator><![CDATA[Ashoat Tevosyan]]></dc:creator>
            <pubDate>Thu, 11 Jun 2020 20:29:34 GMT</pubDate>
            <atom:updated>2020-06-11T20:29:34.501Z</atom:updated>
            <content:encoded><![CDATA[<p>Flow library definitions for React Navigation 5 are <a href="https://github.com/flow-typed/flow-typed/pull/3843">now available</a> on flow-typed! With this rewrite we’re now able to typecheck much more of the surface area of React Navigation. Libdefs are available for the following packages:</p><ul><li>@react-navigation/core</li><li>@react-navigation/native</li><li>@react-navigation/stack</li><li>@react-navigation/bottom-tabs</li><li>@react-navigation/drawer</li><li>@react-navigation/material-bottom-tabs</li><li>@react-navigation/material-top-tabs</li></ul><h3>ParamList</h3><p>To properly type the navigate function on the navigation prop, we need to pass in the full list of route names, as well as their corresponding params. We call this map a ParamList. Here’s an example of one:</p><pre>type ChatParamList = {|<br>  ThreadList: void,<br>  MessageList: {| threadID: string |},<br>  ComposeThread: {| parentThreadID?: string |},<br>|};</pre><p>Since the navigation prop can navigate to any screen in your app, even if it’s outside the current navigator, it’s important that each screen in your app is represented in the ParamList you pass in to your navigation props. Attempts to navigate to routes not specified in the ParamList will lead to type errors.</p><p>If your app dynamically generates routes, or if there are other reasons preventing you from statically typing all of your routes, you can specify “default” params for any unspecified routes using ParamListBase. These params will be treated as { +[key: string]: mixed, ... }.</p><pre>import type { ParamListBase } from &#39;@react-navigation/core&#39;;</pre><pre>type ChatParamList = {<br>  ...ParamListBase,<br>  ThreadList: void,<br>  MessageList: {| threadID: string |},<br>  ComposeThread: {| parentThreadID?: string |},<br>  ...<br>};</pre><h3>Typing navigators and screens</h3><p>Here’s an example of how you might type a simple app that nests a StackNavigator within a BottomTabNavigator:</p><pre>import {<br>  createBottomTabNavigator,<br>  type BottomTabNavigationProp,<br>} from &#39;@react-navigation/bottom-tabs&#39;;<br>import {<br>  createStackNavigator,<br>  type StackNavigationProp,<br>} from &#39;@react-navigation/stack&#39;;<br>import type { RouteProp } from &#39;@react-navigation/native&#39;;</pre><pre>type TabParamList = {|<br>  Calendar: void,<br>  Chat: void,<br>  Friends: void,<br>|};<br>type ChatParamList = {|<br>  ThreadList: void,<br>  MessageList: {| threadID: string |},<br>  ComposeThread: {| parentThreadID?: string |},<br>|};<br>type GlobalParamList = {|<br>  ...TabParamList,<br>  ...ChatParamList,<br>|};<br>type NavigationRoute = RouteProp&lt;<br>  GlobalParamList,<br>  $Keys&lt;GlobalParamList&gt;,<br>&gt;;</pre><pre>// We limit the possible routes to TabParamList, but make sure to<br>// pass the GlobalParamList to the navigation prop so we can<br>// navigate to other navigators<br>type TabNavigationProp&lt;<br>  RouteName: $Keys&lt;TabParamList&gt; = $Keys&lt;TabParamList&gt;,<br>&gt; = BottomTabNavigationProp&lt;GlobalParamList, RouteName&gt;;</pre><pre>// We pass in a TabNavigationProp below that isn&#39;t constrained to a<br>// specific route. This is so we can type navigator props like<br>// screenOptions, which can be specified as a function that is<br>// passed a navigation prop<br>const Tab = createBottomTabNavigator&lt;<br>  GlobalParamList,<br>  TabParamList,<br>  TabNavigationProp&lt;&gt;,<br>&gt;();</pre><pre>type ChatNavigationProp&lt;<br>  RouteName: $Keys&lt;ChatParamList&gt; = $Keys&lt;ChatParamList&gt;,<br>&gt; = StackNavigationProp&lt;GlobalParamList, RouteName&gt;;</pre><pre>const Stack = createStackNavigator&lt;<br>  GlobalParamList,<br>  ChatParamList,<br>  ChatNavigationProp&lt;&gt;,<br>&gt;();</pre><pre>// Each individual screen should be typed with navigation and route<br>// props for a specific route, so that route.params and<br>// navigation.setParams can be typed correctly<br>function Calendar(props: {|<br>  navigation: TabNavigationProp&lt;&#39;Calendar&#39;&gt;,<br>  route: NavigationRoute&lt;&#39;Calendar&#39;&gt;,<br>|}) {<br>  [...]<br>}</pre><pre>[...]</pre><pre>// Finally we define the navigation structure using the navigators<br>// we&#39;re constructed<br>function Chat() {<br>  return (<br>    &lt;Stack.Navigator&gt;<br>      &lt;Stack.Screen<br>        name=&quot;ThreadList&quot;<br>        component={ThreadList}<br>      /&gt;<br>      &lt;Stack.Screen<br>        name=&quot;MessageList&quot;<br>        component={MessageList}<br>      /&gt;<br>      &lt;Stack.Screen<br>        name=&quot;ComposeThread&quot;<br>        component={ComposeThread}<br>      /&gt;<br>    &lt;/Stack.Navigator&gt;<br>  );<br>}</pre><pre>function App() {<br>  return (<br>    &lt;Tab.Navigator&gt;<br>      &lt;Tab.Screen<br>        name=&quot;Calendar&quot;<br>        component={Calendar}<br>      /&gt;<br>      &lt;Tab.Screen<br>        name=&quot;Chat&quot;<br>        component={Chat}<br>      /&gt;<br>      &lt;Tab.Screen<br>        name=&quot;Friends&quot;<br>        component={Friends}<br>      /&gt;<br>    &lt;/Tab.Navigator&gt;<br>  );<br>}</pre><h3>Custom navigators</h3><p>Let’s start out with a simple custom stack navigator that uses the standard StackView component but specifies a custom router.</p><pre>import {<br>  type StackAction,<br>  type StackNavigationProp,<br>  type ParamListBase,<br>  type Router,<br>  type StackRouterOptions,<br>  type StackNavigationState,<br>  type RouterConfigOptions,<br>  type StackOptions,<br>  type StackNavigationEventMap,<br>  type StackNavigatorProps,<br>  type ExtraStackNavigatorProps,<br>  StackRouter,<br>  CommonActions,<br>  createNavigatorFactory,<br>  useNavigationBuilder,<br>} from &#39;<a href="http://twitter.com/react">@react</a>-navigation/native&#39;;<br>import { StackView } from &#39;<a href="http://twitter.com/react">@react</a>-navigation/stack&#39;;</pre><pre>type ClearScreensAction = {|<br>  +type: &#39;CLEAR_SCREENS&#39;,<br>  +payload: {|<br>    +routeNames: $ReadOnlyArray&lt;string&gt;,<br>  |},<br>|};<br>type ChatRouterNavigationAction =<br>  | StackAction<br>  | ClearScreensAction;</pre><pre>type ChatRouterNavigationProp&lt;<br>  ParamList: ParamListBase = ParamListBase,<br>  RouteName: string = string,<br>&gt; = {|<br>  ...StackNavigationProp&lt;ParamList, RouteName&gt;,<br>  +clearScreens: (routeNames: $ReadOnlyArray&lt;string&gt;) =&gt; void,<br>  +goBackOnce: () =&gt; void,<br>|};</pre><pre>function ChatRouter(<br>  routerOptions: StackRouterOptions,<br>): Router&lt;StackNavigationState, ChatRouterNavigationAction&gt; {<br>  const {<br>    getStateForAction: baseGetStateForAction,<br>    actionCreators: baseActionCreators,<br>    ...rest<br>  } = StackRouter(routerOptions);<br>  return {<br>    ...rest,<br>    getStateForAction: (<br>      lastState: StackNavigationState,<br>      action: ChatRouterNavigationAction,<br>      options: RouterConfigOptions,<br>    ) =&gt; {<br>      if (action.type === &#39;CLEAR_SCREENS&#39;) {<br>        [...]<br>      } else {<br>        return baseGetStateForAction(lastState, action, options);<br>      }<br>    },<br>    actionCreators: {<br>      ...baseActionCreators,<br>      clearScreens: (routeNames: $ReadOnlyArray&lt;string&gt;) =&gt; ({<br>        type: &#39;CLEAR_SCREENS&#39;,<br>        payload: {<br>          routeNames,<br>        },<br>      }),<br>      goBackOnce: () =&gt; state =&gt; ({<br>        ...CommonActions.goBack(),<br>        target: state.key,<br>      }),<br>    },<br>  };<br>}</pre><pre>type ChatNavigatorProps = StackNavigatorProps&lt;<br>  ChatRouterNavigationProp&lt;&gt;,<br>&gt;;<br>function ChatNavigator({<br>  initialRouteName,<br>  children,<br>  screenOptions,<br>  ...rest<br>}: ChatNavigatorProps) {<br>  const { state, descriptors, navigation } = useNavigationBuilder(<br>    ChatRouter,<br>    {<br>      initialRouteName,<br>      children,<br>      screenOptions,<br>    },<br>  );<br>  return (<br>    &lt;StackView<br>      {...rest}<br>      state={state}<br>      descriptors={descriptors}<br>      navigation={navigation}<br>    /&gt;<br>  );<br>}</pre><pre>const createChatNavigator = createNavigatorFactory&lt;<br>  StackNavigationState,<br>  StackOptions,<br>  StackNavigationEventMap,<br>  ChatRouterNavigationProp&lt;&gt;,<br>  ExtraStackNavigatorProps,<br>&gt;(ChatNavigator);</pre><h3>EventMap</h3><p>Finally, let’s consider a fully custom navigator that doesn’t use any React Navigation UI components. In this case you will need to specify the screen options and the “event map” yourself.</p><p>The EventMap is a “synthetic” type, meaning it doesn’t actually type any values used in React Navigation. We use it to type the event objects passed to event listeners. It specifies two things: any custom data the event object will have, and whether the event.preventDefault() function will exist.</p><p>Consider the EventMap for BottomTabNavigator:</p><pre>declare export type BottomTabNavigationEventMap = {|<br>  +state: {|<br>    +data: {| +state: TabNavigationState |},<br>    +canPreventDefault: false,<br>  |},<br>  +focus: {| +data: void, +canPreventDefault: false |},<br>  +blur: {| +data: void, +canPreventDefault: false |},<br>  +tabPress: {| +data: void, +canPreventDefault: true |},<br>  +tabLongPress: {| +data: void, +canPreventDefault: false |},<br>|};</pre><p>Note that only the tabPress and tabLongPress events expose event.preventDefault(), and that only the state event has custom data.</p><p>Finally, let’s consider what a fully custom navigator that uses StackRouter for routing might look like:</p><pre>import {<br>  type ParamListBase,<br>  type StackNavigationProp,<br>  type StackRouterOptions,<br>  type StackNavigationState,<br>  type StackAction,<br>  type NavigatorPropsBase,<br>  type ExtraNavigatorPropsBase,<br>  useNavigationBuilder,<br>  createNavigatorFactory,<br>} from &#39;@react-navigation/state&#39;;</pre><pre>type CustomScreenOptions = {|<br>  +title: string,<br>|};<br>type CustomEventMap = {|<br>  +pressButton: {| +data: void, +canPreventDefault: false |},<br>|};</pre><pre>type CustomRouterNavigationProp&lt;<br>  ParamList: ParamListBase = ParamListBase,<br>  RouteName: string = string,<br>&gt; = {|<br>  ...StackNavigationProp&lt;<br>    ParamList,<br>    RouteName,<br>    CustomScreenOptions,<br>    CustomEventMap,<br>  &gt;,<br>  [...]<br>|};</pre><pre>function CustomRouter(<br>  routerOptions: StackRouterOptions,<br>): Router&lt;StackNavigationState, StackAction&gt; {<br>  [...]<br>}</pre><pre>type NavigatorProps = $Exact&lt;NavigatorPropsBase&lt;<br>  CustomScreenOptions,<br>  CustomRouterNavigationProp&lt;&gt;,<br>&gt;&gt;;</pre><pre>function CustomNavigator({<br>  initialRouteName,<br>  children,<br>  screenOptions,<br>}: Props) {<br>  const { state, descriptors, navigation } = useNavigationBuilder(<br>    CustomRouter,<br>    {<br>      initialRouteName,<br>      children,<br>      screenOptions,<br>    },<br>  );<br>  [...]<br>}</pre><pre>const createCustomNavigator = createNavigatorFactory&lt;<br>  StackNavigationState,<br>  CustomScreenOptions,<br>  CustomEventMap,<br>  CustomRouterNavigationProp&lt;&gt;,<br>  ExtraNavigatorPropsBase,<br>&gt;(CustomNavigator);</pre><p>Thanks for reading! If you have any questions, you can try to reach me on the <a href="https://discord.gg/8ezwRUK">Flow Discord channel</a>, or by creating an issue on the flow-typed <a href="https://github.com/flow-typed/flow-typed/issues">GitHub repo </a>and tagging @ashoat.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7dcf1f9da8b7" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>