Используйте типизацию — React Navigation

В наши дни построение навигации стало фундаментальной особенностью любого мобильного приложения. Когда дело доходит до мира React Native, у нас в кармане есть React Navigation.

В этой статье будет рассказано, как типичная навигация React может быть реализована с использованием TypeScript, в то же время сравнивая различные стратегии использования TypeScript.

И что еще более важно, в нем также будет рассказано, как мы можем максимально использовать функции TypeScript, чтобы иметь возможность создавать более масштабируемую архитектуру навигации.

Предостережение: примеры в этой статье были получены с использованием версии @[email protected].

Предостережение: методы/стратегии, которые будут рассмотрены в этой статье, не являются обязательными, и вы должны строго им следовать, но это всего лишь мои пристрастия, которыми я считаю полезным поделиться с читателями этой статьи. В React Navigation уже есть замечательный хорошо документированный раздел, посвященный использованию машинописного текста. При этом вы уже можете создать потрясающую структуру машинописного текста с реактивной навигацией, просто следуя этой документации.

Создание навигатора стека

Давайте посмотрим, как создать навигатор стека с помощью пакета React Navigation.

См. пример ниже, взятый из React Navigation;

Как видно, здесь нет ничего конкретного о TypeScript, давайте добавим немного TypeScript в этот фрагмент кода.

Выше мы добавили тип ParamList для createStackNavigator. Но откуда нам знать, что createStackNavigator принимает общий тип? Есть несколько способов выяснить это. Всегда было хорошей практикой сначала просмотреть документацию. В данном примере вы уже заметите, что в документации уже есть раздел для этого.

С другой стороны, если предположить, что этот конкретный тип createStackNavigator не задокументирован на веб-сайте, то возможный способ определить, имеет ли функция тип, — просто перейти к определению типа функции. Поначалу это может пугать, так как вокруг будет летать множество типов, интерфейсов, дженериков, но чем больше вы привыкнете переходить к определению типа, тем меньше будет ошеломления.

Обновите!

Если вы хотите иметь дело с дополнительной сложностью машинописного текста, а также хотите игнорировать замечательную утилиту TS от команды React (React.ComponentProps), вы можете продолжить читать эту статью до конца.

Но я боюсь, что этот раздел может быть концом!

Мы сможем получить типизацию для каждого экрана стека и их конфигурацию с помощью React.ComponentProps<typeof YourStack.Screen> И результат будет просто потрясающим.

Полный пример см. ниже:

И да, у него по-прежнему будет intellisense, он по-прежнему будет предупреждать вас, если вы поместите в свой стек несвязанный экран (или, например, экран, которого нет в объявлении типа стека), например что:

Intellisense также будет там:

Он также более чистый, настраиваемый и динамичный:

В заключение следует отметить, что этот подход позволяет нам легко управлять сложными навигационными структурами(по крайней мере, когда мы сравниваем этот конкретный подход с другими подходами в этой статье). Это потому, что хотя у вас будет более чистый JSX, вы также сможете настроить свой routes более динамичным, модульным способом.

Использование TypeScript на шаг впереди

Это действительно не ограничивается объявлением только универсального типа createStackNavigator. Как насчет типа элементов children, которые будут иметь Stack.Navigator? Хотя эта концепция уже довольно хорошо определена в официальной документации, давайте посмотрим ниже, как мы можем поиграть с ней, чтобы получить более несвязанный способ создания структуры.

Упс, тут так много всего происходит… Давайте разделим каждый блок кода на отдельные части.

В верхней части фрагмента кода мы импортируем необходимые модули. Этот импорт включает типы, функции и другие необходимые вещи. Они не интересны, но необходимы :)

Выше мы импортируем компонент View из react-native, чтобы пример можно было продемонстрировать более простым способом.

А теперь самое интересное. RouteConfig, который импортируется из @react-navigation/core, принимает ровно пять типов в качестве универсального типа. И это конкретное определение типа не задокументировано на официальном веб-сайте реактивной навигации, тем не менее, вы уже можете понять это определение типа, просто используя метод перехода к определению типа, как мы упоминали выше.

Несмотря на то, что может показаться излишним/ненужным иметь его в типичном проекте машинописи, основанном на реакции, он имеет несколько преимуществ, которые будут рассмотрены в следующем разделе.

ИнтеллиСенс

Поскольку у нас есть строго типизированный массив маршрутов стека (он же маршруты приложений), каждый элемент массива теперь обязан придерживаться определения типа массива. Это означает, что IntelliSense будет работать сразу после добавления нового элемента в массив.

Кроме того, применение этого типа вынуждает нас обновлять AppStackRoutesType всякий раз, когда в маршруты приложения добавляется новый элемент. В противном случае мы не сможем добавить новый элемент, которого нет в AppStackRoutesType(AppStackParamList).

Картирование маршрутов

А вот и последняя часть, мы создаем навигатор стека, используя createStackNavigator. Тогда просто нужно отобразить массив, который мы создали выше, вместе с его строгим типом.

В конечном итоге мы можем доверять каждому элементу нашего массива, в нем будут правильно типизированные элементы, поэтому можно безопасно использовать расширенный синтаксис.

Это точно была последняя часть?

Ну нет!

Мы все еще можем улучшить типизацию на примере, который мы рассмотрели.

Разница, которую вы могли заметить, заключается в том, что у нас есть StackRoutesType, который принимает универсальный тип и равен типу, который мы уже видели ранее. Но в чем здесь выгода, спросите вы. Лучше ответить на этот вопрос образно.

Если бы мы не решили использовать общий StackRoutesType, нам пришлось бы дублировать типизацию для каждого стека, который у нас есть в приложении.

Поэтому это будет кошмаром, поскольку приложение становится больше. (тут смысл в том, что количество стеков в приложении и сложность приложения прямо пропорциональны, на самом деле это не всегда 100% верное предположение, тем не менее оно подходит для данного конкретного примера)

С другой стороны, см. выше, как теперь становится проще и чище при использовании универсального типа.

Последние фотографии

Давайте сравним, как будет выглядеть типичная функция Stack в двух разных сценариях:

Рисунок 1. Отрисовка экранов всего стека один за другим в JSX.

Рисунок 2. Рендеринг экранов с использованием массива стековых маршрутов, созданного с помощью строго типизированного машинописного текста. 🎉

И еще… А как насчет реквизита Навигатора?

Возможно, нам осталось рассмотреть еще одну вещь, а именно свойства навигатора стека. Глядя на StackNavigatorниже, существует фрагмент конфигураций для одного навигатора. Почему бы не отделить эти конфигурации от JSX?

Начиная со строки 13, мы уже должны быть знакомы с тем, почему мы используем общий тип. Единственная разница в типизации маршрутов стека здесь может заключаться в типе DefaultNavigatorOptions, который импортируется из @react-navigation/core. Само название типа говорит само за себя, это options для навигатора.

Подобно RouteConfigtype, упомянутому выше, он также принимает несколько универсальных типов. Кроме того, имейте в виду, что мы явно подключаем дочерний ключ, поскольку мы уже отображаем Stack.Navigatorдочерние элементы, соответствующие Stack.Screen.

В строке 22 мы создаем совершенно новый объект (или это может быть функция, если она возвращает объект, удовлетворяющий типу параметров навигатора), который будет представлять options нашего навигатора.

В результате в строке 50 этот объект можно безопасно использовать с синтаксисом распространения, если он удовлетворяет заданному типу.

Гораздо чище JSX… ИМО…

Последние фотографии - реквизит навигатора

Давайте снова сравним, как будет выглядеть типичная функция Stack в двух разных сценариях:

Рисунок 1. Конфигурации навигатора стека в JSX.

Рисунок 2. Конфигурации навигатора стека отделены от JSX.

В этой статье мы рассмотрели, как мы можем на самом деле использовать TypeScript и добиться более чистого способа структурирования наших реактивных навигаторов.

Всем удачного дня без ошибок.