Немного контекста

Недавно я начал работать над библиотекой компонентов, которая реализует некоторые спецификации системы проектирования. Это упростит создание более сложных пользовательских интерфейсов и функций веб-сайта, поддерживая согласованность внешнего вида страниц, взаимодействия с пользователем и стиля бренда в целом для продукта, над которым я работаю.

Мы решили создать его с использованием React, styled-components и TypeScript, чтобы каждый компонент было проще абстрагировать, разрабатывать и тестировать. Мы также хотим обрабатывать несколько тем пользовательского интерфейса (темные / светлые), и почему бы и нет, возможно, в будущем поддерживаются другие темы, а у стилизованных компонентов есть потрясающий встроенный поставщик тем, который выполняет именно эту работу.

Итак, давайте посмотрим, как можно реализовать простую кнопку с использованием этих технологий:

конечно, это просто упрощение по сравнению с фактическим компонентом кнопки, но оно позволяет нам понять, как мы начали создавать наши компоненты.

Итак, в зависимости от текущей темы (светлая / темная) наша кнопка будет выглядеть так:

Здорово. Теперь проблема заключалась в том, что нам требовалось несколько стилей (выделенная кнопка, пользовательский значок, разные цвета и т. Д.), Поэтому мы хотели создать очень абстрактный компонент:

И в итоге мы получили примерно следующее:

где каждый помощник выглядел так:

и так далее со всеми другими помощниками (еще раз, я просто упрощаю вещи в приведенном выше примере). Но, как вы можете видеть, здесь мы фактически сравниваем образец с определенным цветом, а затем извлекаем «кортеж» значений, который можно описать следующим образом: [TextColor, BackgroundColor].

Как видите, сделать это в TypeScript довольно просто, но мы реализуем широко используемый шаблон в других языках программирования, таких как Elixir, Haskell… и ReasonML! Итак, что, если мне нужно сопоставить образец с парой? Что, если мне придется произвести более сложные вычисления, чтобы сгенерировать правильную строку? Для такого наркомана FP, как я, это могло бы быть отличной альтернативой TypeScript, так почему бы и нет?

Так вот и возникла идея рефакторинга хотя бы тех помощников, использующих ReasonML, поддерживая совместимость типов с TypeScript.

Как ReasonML упрощает работу

Прежде всего, нам нужно определить наши типы ReasonML. Начнем с ButtonProps типов (пока не будем theme):

если мы попытаемся реализовать хелпер getColor, мы напишем что-то вроде этого:

кажется невероятно естественным написать такую ​​функцию в ReasonML! Сопоставление с образцом - широко используемая функция в языках функционального программирования. Тем не менее, нет стабильной спецификации для его реализации в следующих версиях EcmaScript (есть только предложение и плагин Babel, подробнее здесь).

Взаимодействие между ReasonML и TypeScript

Мы только прикоснулись к причинам, по которым вам стоит попробовать Reason! (Я не смешно, я знаю) Но теперь, когда мы написали нашу функцию ReasonML, как нам вызвать ее из TypeScript? Вы не поверите, но это намного проще, чем вы думаете!

Прежде всего, давайте запишем типы для нашего theme:

Теперь давайте перепишем наши вспомогательные функции с аннотациями типов, чтобы их было легче читать:

Потрясающий! Теперь давайте добавим две новые зависимости в нашу кодовую базу машинописного текста:

первый необходим для компиляции ReasonML в JavaScript через компилятор Bucklescript; второй используется для генерации типов, совместимых с TypeScript (или даже Flow).

Добавим в package.json файл два новых скрипта:

отлично, нам нужно создать новый файл с именем bsconfig.json (который похож на файл package.json в Node.js):

Как видите, вы можете указать, какие типы вам следует сгенерировать. В этом случае мы сгенерируем типы, совместимые с TypeScript. Не хватает только одного; нам нужно указать компилятору BuckleScript, какие функции следует анализировать для генерации типов, и это невероятно легко сделать:

мы можем сделать это, просто добавив [@genType] перед объявлением функции!

Теперь мы готовы к созданию наших функций ReasonML, запустив yarn build:re. Он сгенерирует два новых файла в том же каталоге, что и наш исходный файл .re (допустим, мы назвали его helper.re): helper.bs.js и helper.gen.tsx. Посмотрим, как они выглядят:

helper.bs.js:

Как видите, созданный BuckleScript файл невероятно похож на исходное решение TypeScript, которое мы написали в первом абзаце!

helper.gen.tsx:

это немного сложнее и для работы используется библиотека bs-platform. Но, как видите, он предоставляет типы точно так же, как мы его закодировали в первом абзаце! Он также автоматически добавляет Eslint: disable comments, чтобы он не конфликтовал с вашей конфигурацией Eslint.

Как это круто?

Что вы будете строить с помощью ReasonML и TypeScript? Бьюсь об заклад, ты сделаешь что-нибудь отличное!