How to Structure Navigation in React Native With Typescript | by Tarik | Sep, 2022

Leverage the typings — React Navigation

Photo by Hendrik Morkel on Unsplash

Building navigation has been the fundamental feature of any mobile application these days. When it comes to React Native world, we have React Navigation in our pocket.

This article will go through how a typical React Navigation can be implemented using TypeScript meanwhile comparing different strategies of TypeScript usage.

And more importantly, it will also cover how we can make the most out of TypeScript features to be able to build a more scalable architecture on navigation.

Caveat: The examples in this article have been derived using @react-navigation@6.x version.

Creating Stack Navigator

Let‘s take a look at how to create a stack navigator using the React Navigation package.

See the example below taken from React Navigation;

As can be seen that there is nothing specific about TypeScript here, let’s add a bit of TypeScript to this code snippet.

In the above, we have added the ParamList type for createStackNavigator. But hey, how do we know that createStackNavigator takes the generic type? There are a couple of ways to figure it out. It has always been good practice to review the documentation first. In this given example, you will already notice that there is already a section for it in the docs.

On the other hand, assuming that this specific typing of createStackNavigator is not documented on the website, then a possible way of determining whether the function has the typing would be just jumping to the type definition of the function. It can be intimidating at first since there will be lots of types, interfaces, generics flying around but the more you get into the habit of jumping to the type definition, it will be much less overwhelming.

Taking usage of TypeScript one step ahead

It is indeed not limited to declaring only generic type of createStackNavigator. How about the type of children elements that Stack.Navigator will have?

Oops, there is so much going on here… Let’s divide each code block to separate parts.

At the top of the code snippet, we are importing the necessary modules. These imports include types, functions, and other necessary stuff. They are not interesting but necessary 🙂

Above, we are importing View component from react-native so that the example is demonstrable in a more simple way.

Now, here comes the interesting part. The RouteConfig which is imported from @react-navigation/core takes exactly five types as a generic type. And this particular type definition is not documented on the official react-navigation website, nonetheless, you can already figure this type definition out by just using the method of jumping to the type definition as we mentioned above.

Even though it might seem redundant/not necessary to have it on a typical react-native typescript project, it comes with several benefits which will be covered below section.

Since we have a strictly typed stack routes(aka app routes) array, every element of the array is now obliged to stick with the type definition of the array. This means IntelliSense will work out of the box when adding a new element to the array.

Moreover, applying this type enforces us to update AppStackRoutesType whenever there will be a new element to be added to the app routes. Otherwise, we would not be able to add a new element that does not exist in the AppStackRoutesType(AppStackParamList).

Mapping the routes

Here comes the last part, we are creating the stack navigator using createStackNavigator. Then simply it is just a matter of mapping the array we created above along with the strict type of it.

We can eventually trust every element of our array, it will have correctly typed elements, thus it is safe to use spread syntax.

Was it really the last part?

Well… No!

We can still improve our typings on the example we’ve covered.

The difference you might have noticed is that we have StackRoutesType which takes a generic type and equals the type that we have already seen before. But what is the benefit here you may ask. Better to answer this question in a visualized way.

If we were not to choose to use generic StackRoutesType, we would have to duplicate typings for every stack we have in the app.

Therefore, this would be a nightmare as the app gets bigger. (here the notion is, number of stacks in the app and the complexity of the app are directly proportional, in fact, it is not a always 100% valid assumption, nevertheless it is suitable for this specific example)

On the other hand, see above how it becomes simpler and clean now when using generic type.

Let’s compare how a typical Stack function would look in two different scenarios:

Picture 1: Rendering whole stack screens one by one in JSX.

Picture 2: Rendering screens using the stack routes array created using the strictly typed typescript. 🎉

One more thing… What about Navigator props

We might have one more thing left to consider which is props of the stack navigator. Looking at the below StackNavigator, there exists a chunk of configurations for a single navigator. Why not have these configurations decoupled from JSX?

Starting from Line 13, we should be already familiar with why we use generic type. The bare difference in typing with the stack routes here might be the DefaultNavigatorOptions type, which is imported from @react-navigation/core. The name of the type itself is even self-explanatory, it is options for the navigator.

Similar to RouteConfig type we have mentioned above, it takes also multiple generic types. Besides this, bear in mind that we are explicitly omitting the children key as we are already rendering Stack.Navigator children which correspond to Stack.Screen.

On Line 22, we are creating a brand new object (or it can be a function, as long as it returns an object that satisfies the navigator options type) which will represent the options of our navigator.

As a result, on Line 50, this object can be safely used with spread syntax as long as it satisfies the given type.

Much cleaner JSX… IMO…

Latest pictures – Navigator props

Let’s again compare how a typical Stack function would look in two different scenarios:

Picture 1: Having stack navigator configurations in JSX.

Picture 2: Having stack navigator configurations decoupled from JSX.

News Credit

%d bloggers like this: