React Navigation with Typescript
Tags: react, reactnative, reactnavigation, typescript
Published: 2019-05-14 11:57:05

---
title: React Navigation with Typescript
published: true
description: Snippets to use when building React Native apps in Typescript and using React Navigation
tags: react, reactnative, reactnavigation, typescript
---

So.. You want to build an React Native app with Typescript and you have decided to use React Navigation as navigation library.

You have set all the Typescript stuff up and gets your app running!

You add React Navigation and all is fine!

But.. You add some screens that expects parameters and some that you want to edit the header and so on. There is not much information to find...

Here are some snippets how I have used React Navigation with Typescript.

### *Disclaimer*
There are multiple ways of implementing typed React Navigation. These are only some examples and the naming of things should be considered to fit your application.

Any comments of other ways to solve it is appreciated!

## First, classes vs functions...

I really enjoy using function components with hooks.
But currently there is an issue with hot reloading if using function components.
See: https://github.com/facebook/react-native/issues/10991

It just don't work. There might be solutions where you wrap you functional components around with classes, but hopefully this issue will soon be fixed!
https://mobile.twitter.com/dan_abramov/status/1125846420949434368

I will be using a useNavigation hook based of https://github.com/react-navigation/hooks.
But since the repo isn't very active, I just "stole" this function and modified abit:
```typescript
import { useContext } from 'react';
import {
  NavigationScreenProp,
  NavigationRoute,
  NavigationContext,
} from 'react-navigation';

export function useNavigation<Params>() {
  return useContext(NavigationContext) as NavigationScreenProp<
    NavigationRoute,
    Params
  >;
}
```

So, my examples will be with both classes and functional components.

## Update header title and navigate

#### Class component
```typescript
import React, { Component } from 'react';
import { Button, Text, View } from 'react-native';
import {
  NavigationParams,
  NavigationScreenProp,
  NavigationState,
} from 'react-navigation';

interface Props {
  navigation: NavigationScreenProp<NavigationState, NavigationParams>;
}

class TestScreen extends Component<Props> {
  public static navigationOptions = {
    title: 'Test Screen',
  };

  render() {
    const { navigation } = this.props;
    return (
      <View>
        <Text>Test Screen</Text>
        <Button
          title="Button"
          onPress={() => {
            navigation.navigate('anotherTestScreen');
          }}
        />
      </View>
    );
  }
}

export default TestScreen;
```

Notice, that only screens that is set up directly on a navigation has the navigation property. If you would like a sub-component to have access to navigation you can do like this:

```typescript
import React, { Component } from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationInjectedProps, withNavigation } from 'react-navigation';

class TestComponent extends Component<NavigationInjectedProps> {
  render() {
    const { navigation } = this.props;
    return (
      <Button
        title="Button"
        onPress={() => {
          navigation.navigate('anotherTestScreen');
        }}
      />
    );
  }
}

export default withNavigation(TestComponent);
```

#### Function component
```typescript
import React from 'react';
import { Button, Text, View } from 'react-native';
import { useNavigation } from '../hooks/useNavigation';

const AnotherTestScreen = () => {
  const navigation = useNavigation();
  return (
    <View>
      <Text>Test Screen</Text>
      <Button
        title="Button"
        onPress={() => {
          navigation.navigate('paramScreen', { text: 'Hi!' });
        }}
      />
    </View>
  );
};

AnotherTestScreen.navigationOptions = {
  title: 'Another Test Screen',
};

export default AnotherTestScreen;
```

## Typed params for the screens

#### Class component
```typescript
import React, { Component } from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationScreenProp, NavigationState } from 'react-navigation';

interface NavigationParams {
  text: string;
}

type Navigation = NavigationScreenProp<NavigationState, NavigationParams>;

interface Props {
  navigation: Navigation;
}

class ParamScreen extends Component<Props> {
  public static navigationOptions = ({
    navigation,
  }: {
    navigation: Navigation;
  }) => ({
    title: navigation.state.params ? navigation.state.params.text : '',
  });

  render() {
    const { navigation } = this.props;
    const {
      state: { params },
    } = navigation;
    return (
      <View>
        <Text>Param: {params ? params.text : ''}</Text>
        <Button
          title="Button"
          onPress={() => {
            navigation.navigate('anotherParamScreen', { text: 'Hello!' });
          }}
        />
      </View>
    );
  }
}

export default ParamScreen;
```
Why would you bother with that much extra typings code you might ask yourself? Why not just use `any`? 
Well, this example might not be the best, but the params are now typed and you can get intellisense help in your editor:

![](https://thepracticaldev.s3.amazonaws.com/i/0vvzgo3go4pfghdt16k3.png)

#### Function component
```typescript
import React from 'react';
import { Button, Text, View } from 'react-native';
import {
  NavigationScreenProp,
  NavigationState,
  StackActions,
  NavigationActions,
} from 'react-navigation';
import { useNavigation } from '../hooks/useNavigation';

interface NavigationParams {
  text: string;
}

type Navigation = NavigationScreenProp<NavigationState, NavigationParams>;

const AnotherParamScreen = () => {
  const navigation = useNavigation<NavigationParams>();
  const {
    state: { params },
  } = navigation;
  return (
    <View>
      <Text>Param: {params ? params.text : ''}</Text>
      <Button
        title="Button"
        onPress={() => {
          const resetAction = StackActions.reset({
            index: 0,
            actions: [NavigationActions.navigate({ routeName: 'testScreen' })],
          });
          navigation.dispatch(resetAction);
        }}
      />
    </View>
  );
};

AnotherParamScreen.navigationOptions = ({
  navigation,
}: {
  navigation: Navigation;
}) => ({
  title: navigation.state.params ? navigation.state.params.text : '',
});

export default AnotherParamScreen;

```