Flow — это инструмент статической проверки типов, ориентированный на проверку правильности кода для JavaScript, разработанный и открытый Facebook. Он направлен на то, чтобы предоставить проектам возможность поэтапно внедрять инструмент для каждого файла, не мешая другим инструментам.

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

Первое, что вы можете сделать, это прочитать руководство Flow Начало работы. Вы можете сделать это, но как только вы закончите, я хочу, чтобы вы вернулись сюда, потому что одна вещь, которую вы быстро обнаружите, заключается в том, что Поток сложен, но не в том смысле, что он сложен, а в том, что в нем много движений. части, которые вам необходимо учитывать при настройке среды, которые на момент написания документа Flow не очень хорошо представляются.

Если вы не примете их во внимание с самого начала, вы либо потеряете эффективность, либо получите сильную головную боль, как только поймете, что эти концепции существуют.

Транспиляция

Это необходимо, если вы планируете запускать свой код где угодно, и это объясняется в документации Flow, но я повторю здесь для полноты картины.

Когда вы пишете код Flow, это не настоящий JavaScript, поэтому он фактически не может работать где угодно, вам нужно будет использовать такой инструмент, как babel, для транспиляции и удаления типов Flow из исполняемого кода.

Все, что вам нужно сделать, это установить @babel/preset-flow

// yarn
yarn add -D @babel/preset-flow
// npm
npm install --save-dev @babel/preset-flow

И добавьте его в конфигурацию Babel.

{
  "presets": [
    // ... other presets
    "@babel/preset-flow"
  ],
  // ... other properties
}

Определения типов из сторонних библиотек

После того, как вы установили Flow и попытаетесь запустить его, вы можете обнаружить, что процесс запуска занимает вечность, особенно если вы работаете в существующем проекте, который имеет много зависимостей. Это нормально, потому что Flow просматривает каждый модуль, чтобы найти типизацию и определить разрешение модуля. Во многом это замедление вызвано огромным размером node_modules.

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

# .flowconfig
[ignore]
# ... other ignores
.*node_modules/.*
# ... other config settings

Если вам интересно, как работает синтаксический анализ, Flow построен на ocaml, поэтому любое сопоставление строк использует синтаксис регулярного выражения ocaml.

Но когда вы пытаетесь добавить Flow в существующий модуль, вы можете быть удивлены, обнаружив повсюду ошибки Flow, особенно если вы импортируете сторонние зависимости.

Это связано с тем, что вы полностью проигнорировали node_modules из анализа Flow, поэтому в мире Flow node_modules не существует, а импорт lodash, например, не имеет места для разрешения.

(На самом деле React — единственный пакет, с которым вы не получите ошибок, потому что его типы встроены непосредственно в пакет Flow.)

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

Большинство библиотек, даже если они созданы с помощью Flow, не поставляются вместе с ними в пакете, styled-components — отличный тому пример. Вместо этого они определяются и управляются в flow-typed, репозитории определений типов сторонних библиотек, управляемом сообществом Flow.

Вы бы установили это глобально и использовали бы его в своих проектах, как менеджер пакетов.

# yarn
yarn global add flow-typed
# npm
npm install -g flow-typed

Теперь в корне вашего проекта вы можете запустить flow-typed install, который просканирует ваш package.json и загрузит определения потокового типа в ./flow-typed/npm (вы должны зафиксировать этот каталог).

Если пакет не набран, он будет заглушен комментарием ниже. Если у вас есть время, и вы в конечном итоге заполните заглушку, я настоятельно рекомендую вам отправить PR в потоковую типизацию, сопровождающие довольно активны, и это действительно простой способ окунуть свои руки в программное обеспечение с открытым исходным кодом (OSS), если вы не раньше.

/**
 * This is an autogenerated libdef stub for:
 *
 *   'package-name'
 *
 * Fill this stub out by replacing all the `any` types.
 *
 * Once filled out, we encourage you to share your work with the
 * community by sending a pull request to:
 * https://github.com/flowtype/flow-typed
 */

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

Это делается с помощью выражения ! в строке игнорирования. Например, маленький вариант поставляется с типами потока, поэтому мы можем сообщить Flow, что хотим исключить все node_modules, кроме этой одной библиотеки.

[ignore]
# ... any other ignores
.*node_modules/.*
!.*node_modules/tiny-invariant/.*

Подробнее здесь

К сожалению, вам не сообщат, когда библиотека будет поставляться с типами потока, поэтому вам придется проверить это самостоятельно. Общее эмпирическое правило заключается в том, что библиотеки, разработанные в Facebook, такие как graphql/recoil, или если они получают заглушки с потоковыми типами вместо реальных определений, я быстро проверю node_modules, чтобы узнать, поставляются ли они с потоковыми типами. Если они это сделают, я добавлю исключение и удалю заглушку, чтобы поток мог разрешать реальные типы вместо заглушки any.

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

Лично мои .flowconfig, как правило, имеют !.*node_modules/@.* в качестве стандарта, а также любые дополнительные библиотеки, такие как крошечный инвариант. Таким образом, я могу использовать типы потоков с частной областью действия, если они когда-либо появятся. Кроме того, игнорирование небольшого подмножества пакетов, начинающихся с @, как правило, не оказывает заметного влияния на производительность запуска Flow.

Строгий и свободный стили печати

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

Вы можете прочитать об этом здесь, https://flow.org/en/docs/strict/. Хотя выбор зависит от вас, я бы порекомендовал вам оставить Flow по умолчанию и оставить его свободным, иначе вам будет довольно сложно адаптировать инструмент, особенно в существующем проекте.

По мере того, как вы будете чувствовать себя более комфортно, вы можете обнаружить, что значение постепенно приводит к более строгому синтаксису. Самый простой — ограничить использование Function и вместо этого применить синтаксис типа () => {}.

Сопоставление модулей

При импорте файлов Flow прекрасно понимает js css png etc. Но что, если вы не используете их, что, если вы хотите использовать scss вместо css или webp вместо png?

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

Например, если попытаться импортировать webp файлов и попытаться зарегистрировать их, вы увидите, что возвращается строка. Итак, все, что нам нужно сделать, это создать фиктивный строковый файл и указать все файлы webp, чтобы получить оттуда определения типов.

Начните с создания нового файла в новом каталоге ./flow-mocks с именем empty-string.js и добавьте следующее:

// @flow
export default '';

Затем вы можете добавить настройку в свой .flowconfig

[options]
# ... other options
module.name_mapper.extension='webp' -> '<PROJECT_ROOT>/flow-mocks/empty-string.js'

И это все. Теперь, когда вы импортируете файлы webp, вы получите проверку типов и правильное автозаполнение, если в вашей среде IDE установлен плагин Flow.

Будущие функции по умолчанию

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

Но поскольку вы настраиваете Flow сейчас, вероятно, в ваших интересах включить их с самого начала.

Когда вы создаете тип объекта Flow, его можно определить как точный {| |} или неточный { ... } . По умолчанию в Flow есть объекты, которые не определяют это явно { } как неточное. В будущем Flow планирует сделать точно новую норму, но включить ее можно уже сейчас:

[options]
# ... other options
exact_by_default=true

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

Звучит очень красиво, но на самом деле все, что требуется, это чтобы модули теперь имели явно типизированный экспорт.

// This would have worked before
export const func = (v) => { console.log(v); };
// But now you have to do this
export const func = (v: string): void => { console.log(v); };

Как и exact_by_default, изначально он отключен, но его можно легко включить в параметрах (начиная с версии 0.134.0 он включен по умолчанию, и этот параметр больше не нужен):

[options]
# ... other options
types_first=true

Линты — это еще одна область, которую мы должны настроить. Нас интересуют два, deprecated-type и deprecated-utility, которые не позволят нам использовать уже устаревшие наборы функций. Мы можем добавить это в раздел lint нашей конфигурации.

[lints]
# ... other lints
deprecated-type=error
deprecated-utility=error

Flow применяет очень строгие правила кодирования. Иногда это настолько строго, что вы просто не можете их обойти, возможно, система типов/определения еще не поддерживаются, но вы знаете, что код работает и хорошо протестирован.

Вот где в игру вступают подавляющие комментарии. По умолчанию применение подавления к строке кода приведет к подавлению всех ошибок, что обычно не является тем, чего вы хотите, в основном вы хотите подавить тот единственный тип ошибки, который блокирует вас, и получать уведомления обо всем, что может вызвать ненадежность в вашем коде. кодовая база. Вы можете сделать это с помощью кодов подавления, о которых вы не будете уведомлены как о необходимости по умолчанию. Включить это просто

[options]
# ... other options
include_warnings=true

Именование и использование типов

Когда вы определяете тип в Flow, вы также должны дать имя. Обычно принято называть их PascalCasing. Но дальше дело за вами.

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

Мне нравится следовать соглашению Uber, представленному в их библиотеке BaseWeb, где все их типы имеют суффикс T. Таким образом, всякий раз, когда вы видите переменную, вы сразу узнаете, является ли она переменной JavaScript или типом Flow. Это упрощает размышления об уникальных именах типов, подобно тому, как React добавляет ко всем хукам префикс ключевого слова use.

// Don't
const ref: RefObj = useRef();
// Do
const ref: RefT = useRef();

Постоянные релизы

Flow выпускает новые версии каждые пару недель. Это очень важно, потому что Flow — это активный проект, в который постоянно вносятся улучшения и изменения по мере того, как инструмент продолжает совершенствоваться и внедряются лучшие стандарты для обеспечения лучшего статического анализа.

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

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

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

Последние мысли

Учитывая, что Flow существует уже много лет, конечно, есть еще много настроек, которые вы хотели бы внести в свой проект, чтобы он подходил именно вам. Но цель никогда не заключалась в том, чтобы предоставить универсальное руководство для всех, а вместо этого дать новым пользователям чувство уверенности. Многие из этих идей сбивали меня с толку, когда я только начинал, и я повторяю их, продолжая пропагандировать этот инструмент.

Если у вас есть какие-либо вопросы или вы хотите узнать больше, задайте их на Stackoverflow, официальном сервере Discord, или оставьте комментарий ниже!