Депрекация React-компонента с помощью перегрузок TypeScript¶
Важное замечание
Учтите, что решение из этой статьи закрывает очень конкретную проблему и ситуацию. Это не рекомендуемый способ поддерживать версии компонентов внутри проекта.
Что за ситуация?¶
Представим, что у вас есть монорепозиторий, а внутри него пакет с общими компонентами, которые используют разные приложения. Все потребители подключают этот пакет через workspace:^. Поскольку пакет с компонентами не публикуется в registry, разрешение версии на этапе публикации здесь не важно: workspace:^ просто означает, что каждый пакет в монорепозитории, который от него зависит, всегда получает текущую локальную реализацию — живую версию, а не снимок из registry.
Но что произойдет, если вы захотите внести breaking change в компонент: например, изменить у Card радиус скругления, цвет фона заголовка и тень? Это значит, что все потребители потенциально могут сломаться, верно?
Кто-то может предложить создать новый компонент, а старый пометить как deprecated. Но тогда всем потребителям придется менять имя используемого компонента. Кроме того, у вас появятся два разных компонента в двух разных директориях (если вы хорошо организуете код), а это создает еще больше шума.
Мне хотелось чего-то более простого и устойчивого. Цели были такие:
- Сохранить то же имя компонента
- Видеть, что именно устарело
- Иметь простой способ переключаться между старой и новой версиями
Один из способов сделать это¶
В TypeScript, как и в некоторых других языках вроде Java, есть полезная концепция перегрузок. Перегрузка означает, что у вас может быть одно и то же имя, например для функции, но при вызове с разными аргументами вы получаете разную реализацию. А React-компоненты, как мы знаем, по сути являются функциями. Отлично.
Допустим, у меня есть очень простой компонент Card:
Он выглядит так:
Но я хочу создать новую версию компонента Card, у которой будут другие радиус скругления, цвет фона заголовка и тень, а старую версию пометить как deprecated.
Для функции Card можно создать перегрузку. Посмотрим как.
Сначала я создал новый интерфейс для пропсов новой карточки. В нем есть единственный проп new, который всегда равен true. Чуть позже посмотрим, как он используется.
(Можно пойти дальше и завести v1, если вы планируете поддерживать больше одной версии, но, пожалуйста, не делайте так: этот подход не заменяет версионирование пакетов.)
Затем назовем старую функцию Card как LegacyCard, а новую версию — NewCard. В NewCard мы внесем все breaking changes, которые хотели.
Теперь интересная часть — перегрузка:
Обратите внимание, что у нас есть три определения функции Card: одно для старой версии, одно для новой и одно для самой перегрузки. Также заметьте, что вариант со старыми CardProps помечен как @deprecated.
В итоге мы все равно экспортируем один Card:
Вот и все — теперь можно начинать использовать компонент. Посмотрим, как выглядит реализация Card в Storybook. Обратите внимание: один Card зачеркнут, а другой выглядит нормально. Причина в том, что у второго компонента Card есть дополнительный проп new.
А вот как это выглядит:
Готово, на этом все.
Для AI я также создал небольшой SKILL, который может сделать это за вас. Его можно адаптировать под свои задачи. Найти его можно здесь: deprecate-react-component skill
Источник: https://dev.to/mbarzeev/deprecating-a-react-component-using-typescript-overload-2ka


