Flow + Tcomb = Набранный Js

Рано или поздно все приходят к выводу, что нам нужна строгая типизация.

Почему? Потому что проект растёт, приобретая всё больше «если»; Функциональное программирование - все есть функции - это неправда, в консоли мне просто сказали "неопределенное - это не функция".

Эти проблемы появляются всё чаще, отслеживать становится сложнее, возникает вопрос — давайте строго набирать, хотя бы на этапе написания кода, который он подскажет. Вы знаете эту шумиху: TypeScript — это расширенная версия JavaScript. Маркетинговый бакалавриат. Мы честно пытались, грубо говоря, переименовать проект из JS в TS — не получилось.

Он не компилируется, потому что некоторые вещи неверны с точки зрения TypeScript. Это не значит, что TypeScript — плохой язык, но чтобы продвинуть идею надмножества и вот так меня подвести, TypeScript оказался не таким, как я ожидал.

Как только вы вычеркнете TypeScript, останется ровно одна альтернатива: Flow. Что я могу сказать о Флоу? Flow — это очень круто, потому что он заставит вас изучить систему типов OCaml, хотите вы этого или нет. Flow написан на OCaml. Он имеет гораздо более строгий и гораздо более мощный вывод типов, чем TypeScript. Вы можете частично переписать проект во Flow. Количество бонусов, которые приносит вам Flow, сложно описать.

Но, как всегда, есть пара «но».

Хорошие.

Мы начинаем видеть подобные вещи — это часть редуктора:

  
  
  
  
  
  
   

type BuyTicketActionType = {| type: BuyTicketActionNameType, |} type BuyTicketFailActionType = {| type: BuyTicketFailActionNameType, error: Error, |}

Трубы "|" внутри фигурных скобок означает строгий тип — только эти поля и ничего более.

На вход редуктора должны поступать только следующие действия:

type ActionsType = | BuyTicketActionType | BuyTicketFailActionType ;

Flow прекрасно это подтверждает. Казалось бы, все отлично, но нет. Flow работает только с типами.

Приходится писать извращения:

type BuyTicketActionNameType = 'jambler/popups/buyBonusTicket/BUY_TICKET'; const BUY_TICKET: BuyTicketActionNameType = 'jambler/popups/buyBonusTicket/BUY_TICKET';

Потому что вы не можете объявить константу и сказать, что такой-то тип является значением этой константы; Проблема курицы и яйца, константа — это уже код, который необходимо набирать, а типы не должны взаимодействовать с кодом.

Поэтому приходится говорить, что тип BuyTicketActionNameType — это какая-то строка, а затем, что константа BUY_TICKET имеет тот же тип, исключительно ради проверки совпадения строки.

Немного извращенный.

Что еще.

Эти строгие шрифты очень классные, с ними очень удобно выявлять опечатки и так далее; просто они не понимают оператор распространения :

case OPEN_POPUP: { const { config } = action; return { .

state, isOpen: true, config, }; }

То есть у вас есть состояние описанного типа, и вы говорите вернуть спред из состояния и новых полей; Flow не понимает, что мы будем распространять те же поля, которые должны вернуть.

Обещают когда-нибудь это исправить, Flow очень быстро развивается (пока есть обходной путь ).

Но главная проблема Flow в том, что типы, которые вы пишете, напоминают предвыборную программу депутатов Верховной Рады Украины.

То есть вы предполагаете, что туда придут определенные типы, но на самом деле туда приходит не совсем то, что вы ожидаете.

Например, вы ожидаете, что пользователь всегда будет заходить в компонент, но иногда туда приходит null — всё, вы не поставили вопросительный знак, Flow его никак не поймает. То есть полезность Flow начинает падать, как только вы начинаете применять его к существующему проекту, где у вас в голове вроде бы есть понимание происходящего, но на деле не всегда происходит так, как вы задумали.

.

Есть также бэкенд-программисты, которые любят менять форматы данных, не уведомляя вас об этом.

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

Но как только вы начнете писать схемы JSON, вы получите два источника типизации: схемы JSON и Flow. Поддержание их согласованности — тот же миф, что и поддержание актуальности JSDoc. Говорят, где-то есть программисты, которые поддерживают JSDoc в актуальном состоянии, но я их не встречал.

И тут на помощь приходит самый потрясающий плагин, который для меня является убийственной функцией, почему теперь я практически в любом проекте выберу Flow вместо TypeScript. Это tcomb (babel-plugin-tcomb).

Что он делает? Он принимает типы Flow и реализует проверки во время выполнения.

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

Неважно, откуда вы взяли эти данные: в результате парсинга JSON и так далее, и так далее.

Отличная вещь, как только подключаешь его к проекту, следующие два дня понимаешь, что все Flow-типы, которые ты написал, на самом деле неправильные.

Он говорит: «слушай, ты тут написал, что грядет Event — это на самом деле React’s SyntheticEvent».

Вы не думали, что в React все события являются SyntheticEvents. Или там: «слушай, у тебя ноль».

И каждый раз он падает, падает, падает. Честно говоря, вылетает только в режиме разработки.

Тот странный момент, когда в продакшене всё продолжает работать, но разработка невозможна.

Но это очень помогает. У нас есть функции и типы, tcomb просто преобразуется в утверждения; но самое коварное то, что он выполняет Object.freeze() для всех типизированных объектов — это значит, что вы не можете просто добавить поле к объекту, вы даже не можете ничего запихнуть в массив.

Вам нравится неизменность? Ну вот. С tcomb вы будете писать неизменяемый код, нравится вам это или нет. Это краткое изложение части отчета Хайп против реальности: год жизни с изоморфным React-приложением (Илья Климов) ПС я сейчас перевожу свой фан-проект на потоке.

Хотелось бы чего-то странного, чтобы код компонента был выше объявления типа для реквизита.

До:

import React from 'react' import PropTypes from 'prop-types' const MyComponent = ({ id, name }) => { //.

} MyComponent.propTypes = { id: PropTypes.number, name: PropTypes.string, }

После:

// @flow import React from 'react' const MyComponent = ({ id, name }: Props) => { //.

} type Props = { id: number, name: string, }

Но теперь ESLint жалуется на нарушение правила не использовать перед определением .

И вы не можете изменить конфигурацию ESLint в CRA. И выход есть, я им еще раз прекрасно пользуюсь реагировать-приложение-перемонтировано .

Кстати, тоже помогло подключить tcomb, вся магия внутри config-overrides.js .

И вишенка на торте.

Поток + абсолютные пути для импорта:

# .

flowconfig [options] module.system.node.resolve_dirname=node_modules module.system.node.resolve_dirname=src

Теги: #вискас #разработка сайтов #JavaScript #react.js

Вместе с данным постом часто просматривают: