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