Более доступная, удобочитаемая, адаптированная для мобильных устройств и актуальная версия этой истории доступна в моем личном блоге!

Этот пост является частью неофициальной серии небольших статей, посвященных использованию типов 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. Мы видим, что использование дженериков не только придает гибкость нашему типу, но также поможет в будущем, когда мы захотим расширить использование этого компонента, чтобы его можно было использовать с еще большим количеством ресурсов.

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

Удачного дня.
Максим