Проверка типов с помощью TypeScript¶
React Navigation написан на TypeScript и экспортирует определения типов для TypeScript-проектов.
Проверка типа навигатора¶
Для проверки типа имени и параметров маршрута необходимо создать объектный тип с отображениями имени маршрута на параметры маршрута. Например, в нашем корневом навигаторе есть маршрут Profile, который должен иметь параметр userId:
1 2 3 | |
Аналогичным образом необходимо поступить с каждым маршрутом:
1 2 3 4 5 | |
Указание undefined означает, что маршрут не имеет параметров. Тип объединения с undefined (например, SomeType | undefined) означает, что параметры являются необязательными.
После того как мы определили отображение, необходимо указать навигатору, что его нужно использовать. Для этого мы можем передать его в качестве generic функции createXNavigator:
1 2 3 4 5 | |
И тогда мы сможем его использовать:
1 2 3 4 5 6 7 8 9 | |
Это обеспечит проверку типов и intelliSense для реквизитов компонентов Navigator и Screen.
Замечание
Тип, содержащий сопоставления, должен быть псевдонимом типа (например, type RootStackParamList = { ... }). Он не может быть интерфейсом (например, interface RootStackParamList { ... }). Он также не должен расширять ParamListBase (например, interface RootStackParamList extends ParamListBase { ... }). Это приведет к некорректной проверке типов, которая позволит передавать некорректные имена маршрутов.
Проверка типов экранов¶
Для проверки типов экранов нам необходимо аннотировать реквизит navigation и реквизит route, получаемые экраном. Пакеты навигаторов в React Navigation экспортируют общие типы для определения типов реквизитов navigation и route из соответствующего навигатора.
Например, для нативного стекового навигатора можно использовать NativeStackScreenProps.
1 2 3 4 5 6 7 8 9 10 11 12 | |
Тип принимает 3 дженерика:
- Объект списка param, который мы определили ранее
- Имя маршрута, к которому относится экран
- ID навигатора (необязательно).
Если у вас есть реквизит id для навигатора, то можно сделать так:
1 2 3 4 5 | |
Это позволяет нам проверять имена и параметры маршрутов, по которым осуществляется навигация с помощью navigate, push и т.д. Имя текущего маршрута необходимо для проверки параметров в route.params и при вызове setParams.
Аналогично можно импортировать StackScreenProps для @react-navigation/stack, DrawerScreenProps из @react-navigation/drawer, BottomTabScreenProps из @react-navigation/bottom-tabs и так далее.
Затем вы можете использовать тип Props, определенный выше, для аннотирования вашего компонента.
Для функциональных компонентов:
1 2 3 | |
Для классовых компонентов:
1 2 3 4 5 | |
Типы navigation и route можно получить из типа Props следующим образом:
1 2 3 | |
В качестве альтернативы можно аннотировать реквизиты navigation и route по отдельности.
Чтобы получить тип для реквизита navigation, необходимо импортировать соответствующий тип из навигатора. Например, NativeStackNavigationProp для @react-navigation/native-stack:
1 2 3 4 5 6 | |
Аналогично можно импортировать StackNavigationProp из @react-navigation/stack, DrawerNavigationProp из @react-navigation/drawer, BottomTabNavigationProp из @react-navigation/bottom-tabs и т.д.
Чтобы получить тип для реквизита route, необходимо использовать тип RouteProp из @react-navigation/native:
1 2 3 4 5 6 | |
Мы рекомендуем создать отдельный файл types.tsx, в котором хранить типы и импортировать их в файлы компонентов вместо того, чтобы повторять их в каждом файле.
Вложенные навигаторы¶
Проверка типов экранов и параметров во вложенном навигаторе¶
Вы можете переходить к экрану во вложенном навигаторе, передавая свойства screen и params для вложенного экрана:
1 2 3 4 | |
Чтобы проверить это, необходимо извлечь параметры из экрана, содержащего вложенный навигатор. Это можно сделать с помощью утилиты NavigatorScreenParams:
1 2 3 4 5 6 | |
Комбинирование навигационных реквизитов¶
При вложении навигаторов навигационный реквизит экрана представляет собой комбинацию нескольких навигационных реквизитов. Например, если у нас есть вкладка внутри стопки, то реквизит navigation будет содержать как jumpTo (из навигатора вкладок), так и push (из навигатора стопки). Чтобы упростить объединение типов из нескольких навигаторов, можно использовать тип CompositeScreenProps:
1 2 3 4 5 6 7 8 | |
Тип CompositeScreenProps принимает 2 параметра, первый - тип реквизита для первичной навигации (тип для навигатора, которому принадлежит данный экран, в нашем случае - навигатор вкладок, содержащий экран Profile) и второй - тип реквизита для вторичной навигации (тип для родительского навигатора). Первичный тип всегда должен иметь в качестве второго параметра имя маршрута экрана.
Для нескольких родительских навигаторов этот вторичный тип должен быть вложенным:
1 2 3 4 5 6 7 | |
Если аннотировать свойство navigation отдельно, то вместо него можно использовать CompositeNavigationProp. Использование аналогично CompositeScreenProps:
1 2 3 4 5 6 7 8 | |
Аннотирование useNavigation¶
Для аннотирования свойства navigation, которое мы получаем от useNavigation, мы можем использовать параметр type:
1 2 3 | |
Важно отметить, что это не совсем безопасно для типов, поскольку используемый параметр типа может быть некорректным, а мы не можем проверить его статически.
Аннотирование useRoute¶
Для аннотирования свойства route, которое мы получаем от useRoute, мы можем использовать параметр типа:
1 | |
Важно отметить, что это не полностью безопасно для типов, подобно useNavigation.
Аннотирование options и screenOptions¶
Когда вы передаете компоненту Navigator свойство options для Screen или screenOptions, они уже проверены на соответствие типу, и вам не нужно делать ничего особенного. Однако иногда может потребоваться извлечь опции в отдельный объект и снабдить его аннотацией.
Для аннотирования опций необходимо импортировать соответствующий тип из навигатора. Например, StackNavigationOptions для @react-navigation/stack:
1 2 3 4 5 | |
Аналогично можно импортировать DrawerNavigationOptions из @react-navigation/drawer, BottomTabNavigationOptions из @react-navigation/bottom-tabs и т.д.
При использовании функциональной формы options и screenOptions можно аннотировать аргументы тем же типом, который использовался для аннотирования реквизитов navigation и route.
Аннотирование ref на NavigationContainer¶
Если вы используете метод createNavigationContainerRef() для создания ссылки, то можете аннотировать ее для проверки типов навигационных действий:
1 2 3 4 5 6 7 | |
Аналогично для useNavigationContainerRef():
1 2 3 4 5 6 7 | |
Если вы используете обычный объект ref, то в тип NavigationContainerRef можно передать generic.
Пример при использовании хука React.useRef:
1 2 3 4 5 6 7 | |
Пример использования React.createRef:
1 2 3 4 5 6 7 | |
Указание типов по умолчанию для useNavigation, Link, ref и т.д.¶
Вместо того чтобы вручную аннотировать эти API, можно указать глобальный тип для корневого навигатора, который будет использоваться в качестве типа по умолчанию.
Для этого можно добавить этот фрагмент в кодовую базу:
1 2 3 4 5 | |
Интерфейс RootParamList позволяет React Navigation узнать о параметрах, принимаемых вашим корневым навигатором. Здесь мы расширяем тип RootStackParamList, так как это тип параметров для нашего стекового навигатора в корне. Название этого типа не имеет значения.
Указание этого типа важно, если вы часто используете в своем приложении useNavigation, Link и т.д., поскольку это обеспечит безопасность типов. Это также обеспечит правильную вложенность реквизита linking.
Организация типов¶
При написании типов для React Navigation есть несколько вещей, которые мы рекомендуем использовать для упорядочивания.
- Хорошо создать отдельный файл (например,
navigation/types.tsx), который будет содержать типы, относящиеся к React Navigation. - Вместо того чтобы использовать
CompositeNavigationPropнепосредственно в компонентах, лучше создать вспомогательный тип, который можно использовать повторно. - Указание глобального типа для корневого навигатора позволит избежать ручных аннотаций во многих местах.
С учетом этих рекомендаций файл, содержащий типы, может выглядеть примерно так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
Теперь при аннотировании компонентов можно написать:
1 2 3 4 5 6 7 8 | |
Если вы используете хуки, такие как useRoute, вы можете написать:
1 2 3 4 5 6 7 8 9 | |