Более доступная, удобочитаемая, адаптированная для мобильных устройств и актуальная версия этой истории доступна в моем личном блоге!
Этот пост является частью неофициальной серии небольших статей, посвященных использованию типов Flow, которые я обнаружил и нашел полезными за последние несколько месяцев. Первую статью из этой серии можно найти здесь.
Создание общих компонентов React может быть отличным способом упростить кодовую базу проекта. Комбинируя перекрывающиеся функции в одном компоненте, мы уменьшаем энтропию компонентов и, таким образом, сокращаем объем необходимого тестирования. Однако ввод общих компонентов React поначалу может быть немного хлопотным, особенно когда вы только начинаете работать с Flow. Этот пост будет посвящен одному примеру универсального компонента React, который я изо всех сил пытался напечатать несколько месяцев назад, и тому, как универсальные шаблоны Flow помогли мне не только преодолеть проблемы с набором текста, но и создать масштабируемый тип для этого компонента.
От нескольких типизированных компонентов к одному
В проекте, над которым я работал, мне приходилось обрабатывать несколько ресурсов (названных здесь Resource1, Resource2, Resource3,… для простоты). Каждый ресурс имел свой собственный связанныйList компонент (Resource1List, Resource2List,…), каждый из которых был довольно похож на другие с точки зрения реализации, поскольку сами ресурсы были совершенно такими же, за исключением нескольких различий. Ниже вы можете увидеть типы Resource1 и Resource2:

Итак, учитывая эти спецификации, я хотел создать один ResourceList компонент для отображения элементов данного ресурса. Его свойства будут включать функцию обратного вызова onItemClick, которая принимает в качестве аргумента переменную этого типа ресурса. Вот первый тип, который я написал для свойств компонента ResourceList:

Теперь, когда компонент типизирован, следующий шаг состоит в попытке использовать его с одним из наших ресурсов. Вот как ResourceList можно использовать, например, для Resource1:

Это момент, когда я столкнулся с основной проблемой. Учитывая способ, которым я набрал этот компонент, запуск Flow против кода в приведенном выше примере выдает ошибку:

В типах ресурсов, которые мы объявили выше (Resource1, Resource2,…), вы можете видеть, что ключ поля «id» каждого ресурса не совпадает. Таким образом, всякий раз, когда мы будем использовать этот компонент и писать onItemClick функцию для ресурса, Flow выдаст вам ошибку, сообщающую нам, что свойства других ресурсов отсутствуют.
Как использовать дженерики
Чтобы преодолеть такую ситуацию, могут быть очень практичными дженерики. Вот как мы можем набрать этот компонент и исправить эту проблему:
- мы можем предоставить общий
BasePropsтип, который принимает общий типT - используйте
TвнутриBasePropsдля нашейonItemClickфункции, которая будет принимать элемент типаTв качестве аргумента и, таким образом, иметь типT => void - объявить
Resource1Props,Resource2Propsи т. д. на основанииBaseProps - напишите тип
Propsкак перечислениеResource1Props,Resource2Propsи т. д.
Полученный код выглядит так:

Запуск потока с этим типом должен выводить следующее:

Теперь мы правильно набрали наш общий компонент списка благодаря Flow. Мы видим, что использование дженериков не только придает гибкость нашему типу, но также поможет в будущем, когда мы захотим расширить использование этого компонента, чтобы его можно было использовать с еще большим количеством ресурсов.
Если вам понравилась эта статья, не забудьте нажать кнопку Хлопнуть, и если у вас есть другие вопросы, я всегда доступен в Твиттере или на моем сайте. Вы также можете подписаться на мою Среднюю публикацию, чтобы не пропустить мой следующий пост.
Удачного дня.
Максим