Написание более чистого и безопасного JavaScript с типами сумм

У JavaScript очень плохая репутация в большинстве сообществ разработчиков. Настолько, что фраза «Написание более чистого и безопасного JavaScript…» в названии может показаться большинству читателей излишней. Во многом это связано с нечеткой типизацией, недопустимыми значениями и ужасной цепочкой тернарных выражений или, не дай бог, операторами if для их обработки. В JavaScript все функции работают по принципу «притвориться, что вы получаете то, о чем просили». Если значение не соответствует типу операции, которую вы выполняете, что ж, очень плохо. Чтобы спастись от этого, вы можете писать проверки во время выполнения, добавлять проверки типов и т. Д., Но суть проблемы до сих пор остается нерешенной.

Давайте поучимся у Haskell

У функциональных языков программирования, таких как Haskell, есть четкое решение для этого. Типы сумм! Тип суммы (или Tagged Union) - это алгебраический тип данных, который описывает значения, которые могут принимать несколько разных типов. Популярные примеры в haskell - это монада Maybe (для обработки допустимости значений) и монада Either (для обработки ошибок).

Не волнуйся. Может, я ничего не знаю о монадах Либо (видите, что я там делал?). Все, что нам нужно знать, это то, что Sum Type имеет несколько именованных конструкторов.

В Haskell тип Sum выглядит примерно так:

Здесь MetalGenre - это тип, а ProgMetal, DeathCore - конструкторы этого типа.

Действительно популярным и полезным примером типа Sum в функциональном мире является тип Maybe. В Haskell Maybe - это монада, которая обертывает значение и помогает вам убедиться, что недопустимые значения не обрабатываются, что позволяет вам писать более безопасные функции.

Вот как выглядит определение Maybe в Haskell:

Теперь все допустимые значения будут заключены в Just, а все недопустимые значения будут заключены в Nothing. Таким образом, мы можем обрабатывать недопустимые значения чисто и элегантно и быть уверенными в том, что функция вызывается только для действительных значений.

Вы можете подумать: «Но разве это не возможно только потому, что Haskell - это статически типизированная красота, а JavaScript - порождение сатаны?». Может, нет. (Шутка уже устарела)

EnumFP

Бесстыдное оповещение о самоподключении!
У меня есть библиотека, чтобы помочь с этим! (Сказал каждый разработчик JavaScript).
EnumFP [https://github.com/phenax/enum-fp] (PR приветствуются)

EnumFP - это простой и легкий способ создания типов Sum в JavaScript. Вдохновленная великолепием Haskell, библиотека написана с учетом требований безопасности.

Вот как мог бы выглядеть пример жанра металла с EnumFP.

Может быть?

Концепция того, что делает Maybe, важнее самой реализации. Может быть, и есть содержание значения таким образом, чтобы вы могли выполнять ряд операций с контейнером и не беспокоиться о достоверности вводимых данных.

Используя EnumFP, вы можете реализовать простую программу Maybe и несколько служебных функций. EnumFP также позволяет добавлять описания аргументов. В этом примере используется функция caseOf, которая похожа на match, но для частичного применения).

Gist Link

Здесь
fmap возвращает новое значение Maybe и запускает функцию над значением внутри в случае Just и игнорирует Nothing. (Как Array.prototype.map)
mjoin разворачивает заданный вложенный объект Maybe. Поскольку многие монады, такие как Maybe, не зависят от значения внутри, вы можете поместить монаду внутрь другой монады (это то, что она сказала) (например, Array.prototype.flatten)
chain сопоставляет объект "Maybe" и затем выравнивает полученный вложенный объект "Maybe". (Как Array.prototype.flatMap).

Давайте воспользуемся этим и напишем функцию, которая принимает экземпляр User и дает вам имя, не вызывая ошибки из-за недопустимого пользователя или недопустимого имени.

Gist Link

В приведенном выше примере мы сначала преобразуем пользователя в безопасного пользователя, заключив его в объект Maybe. Затем мы получаем имя пользователя с помощью функции prop. Функции prop и head здесь вместо того, чтобы возвращать значение, заключают значение в объект Maybe. Вот почему, чтобы отобразить его, а затем развернуть, мы используем цепочку вместо fmap.

Работа с React

Да, EnumFP хорошо работает с React! (Переход от одного перенаселенного сообщества к другому).

С новыми хуками реакции, представленными в 16.7, было бы грехом не упомянуть об этом здесь. EnumFP поставляется с хуком useReducer, который представляет собой простую оболочку для useReducer реакции.

Не хотите обновляться до 16.7? Вы все еще смотрите повторы «Сайнфельда»? Хотите подождать, пока ваши внуки помогут вам с обновлением… и… прогулкой?

Не стоит беспокоиться. Также есть HOC.

Подробнее об интеграции с React вы можете узнать здесь.

И это не ограничивается только состоянием компонентов. Вы можете использовать Sum Types для работы с любыми перечисляемыми значениями состояния. От обработки состояний Success, Pending и Failure для любого действия до содержания значений в зависимости от его типа или действительности. Типы сумм предназначены для того, чтобы все это очистить.

Заключение

Это только верхушка айсберга. В мире функционального программирования скрывается гораздо больше этих удивительных идей, ожидающих перехода на другие языки. Пребывание в сообществе JavaScript на какое-то время заставило меня понять, что не все так плохо. То, что нам не хватает в языковых функциях и стандартной библиотеке, мы компенсируем разнообразием библиотек, которые устанавливаются с помощью npm, а сильное сообщество постоянно работает над тем, чтобы «снова сделать JS великим». Итак, давайте вместе построим стену между нами и плохим кодом. Ковфефе.