Проверка типов с помощью 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 |
|