Статьи

Написание лучшего JavaScript с Flow

Как часто вы обнаруживали ошибку в каком-то коде, только чтобы обнаружить, что ошибка — это нечто простое, чего следовало бы избежать? Может быть, вы передали аргументы функции в неправильном порядке, или, возможно, вы пытались передать строку вместо числа? Слабая система типизации JavaScript и желание пытаться привести переменные к разным типам могут быть источником целого класса ошибок, которых просто нет в статически типизированных языках.

30 марта 2017 : статья была обновлена, чтобы отразить изменения в библиотеке Flow.

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

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

Установка

Flow в настоящее время работает на Mac OS X, Linux (64-разрядная версия) и Windows (64-разрядная версия). Самый простой способ установить это через npm:

npm install --save-dev flow-bin

и добавьте его в файл package.jsonscripts

 "scripts": {
  "flow": "flow"
}

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

Начиная

Файл конфигурации с именем .flowconfig Мы можем создать пустой файл конфигурации, выполнив команду:

 npm run flow init

Когда файл конфигурации присутствует, вы можете запустить специальные проверки кода в папке вашего проекта и любых подпапках, выполнив следующую команду в терминале:

 npm run flow check

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

Сервер Flow проверяет файл постепенно, что означает, что он проверяет только часть, которая изменилась. Сервер можно запустить, запустив на терминале команду npm run flow

При первом запуске этой команды сервер запустится и покажет начальные результаты теста. Это обеспечивает гораздо более быстрый и постепенный рабочий процесс. Каждый раз, когда вы хотите узнать результаты теста, запустите flow После того, как вы закончили сеанс кодирования, вы можете остановить сервер, используя npm run flow stop

Проверка типа потока является обязательной. Это означает, что вам не нужно проверять весь код сразу. Вы можете выбрать файлы, которые хотите проверить, и Flow выполнит эту работу за вас. Этот выбор делается путем добавления @flow

 /*@flow*/

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

Вывод типа

Как правило, проверка типа может быть выполнена двумя способами:

  • С помощью аннотаций : мы указываем ожидаемые типы как часть кода, а средство проверки типов оценивает код на основе этих ожиданий.
  • Через вывод кода : инструмент достаточно умен, чтобы вывести ожидаемые типы, просматривая контекст, в котором используются переменные, и проверяя код на основе этого

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

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

Чтобы проиллюстрировать эту функцию, мы можем взять приведенный ниже код в качестве примера:

 /*@flow*/

function foo(x) {
  return x.split(' ');
}

foo(34);

Этот код выдаст ошибку на терминале, когда вы запустите команду npm run flowfoo()

Ошибка будет выглядеть примерно так:

  index.js: 4 
    4: вернуть x.split (''); 
                  ^^^^^ свойство `split`.  Недвижимость не найдена в 
    4: вернуть x.split (''); 
                ^ Номер 
 

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

 /*@flow*/

function foo(x) {
  return x.split(' ');
};

foo('Hello World!');

Как я уже сказал, приведенный выше код не даст никаких ошибок. Здесь мы видим, что Flow понимает, что метод split()stringxstring

Обнуляемые типы

Flow обрабатывает null Он не игнорирует nullnull

Рассмотрим следующий код:

 /*@flow*/

function stringLength (str) {
  return str.length;
}

var length = stringLength(null);

В приведенном выше случае Flow выдаст ошибку. Чтобы это исправить, нам придется обрабатывать null

 /*@flow*/

function stringLength (str) {
  if (str !== null) {
    return str.length;
  }

  return 0;
}

var length = stringLength(null);

Мы вводим проверку на null Flow будет рассматривать этот последний фрагмент как допустимый код.

Тип Аннотации

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

Учтите следующее:

 /*@flow*/

function foo(x, y){
  return x + y;
}

foo('Hello', 42);

Flow не найдет никаких ошибок в приведенном выше коде, потому что оператор +add()

В этом случае мы можем использовать аннотации типов для указания желаемого поведения. Аннотации типов начинаются с префикса :

Если мы добавим аннотации типов к приведенному выше коду, он станет таким, как указано ниже:

 /*@flow*/

function foo(x : number, y : number) : number {
  return x + y;
}

foo('Hello', 42);

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

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

  index.js: 7 
    7: foo («Привет», 42); 
           ^^^^^^^ строка.  Этот тип несовместим с ожидаемым типом параметра 
    3: функция foo (x: число, y: число): число { 
                        ^^^^^^ номер 
 

Если мы передадим число вместо 'Hello' Типовые аннотации также полезны в больших и сложных файлах JavaScript для определения желаемого поведения.

Имея в виду предыдущий пример, давайте посмотрим на различные другие аннотации типов, поддерживаемые Flow.

функции

 /*@flow*/

/*--------- Type annotating a function --------*/
function add(x : number, y : number) : number {
  return x + y;
}

add(3, 4);

Приведенный выше код показывает аннотацию переменной и функции. Предполагается, что аргументы функции add() Если мы передадим любой другой тип данных, Flow выдаст ошибку.

Массивы

 /*-------- Type annotating an array ----------*/
var foo : Array<number> = [1,2,3];

Аннотации массивов имеют вид Array<T>T В приведенном выше коде foo

Классы

Пример схемы класса и объекта приведен ниже. Единственный аспект, о котором следует помнить, это то, что мы можем выполнить операцию ИЛИ среди двух типов, используя | символ. Переменная bar1Bar

 /*-------- Type annotating a Class ---------*/
class Bar{
  x:string;           // x should be string       
  y:string | number;  // y can be either a string or a number
  constructor(x,y){
    this.x=x;
    this.y=y;
  }
}

var bar1 : Bar = new Bar("hello",4);

Объектные литералы

Мы можем аннотировать объектные литералы аналогично классам, указывая типы свойств объекта.

 /*--------- Type annonating an object ---------*/

var obj : {a : string, b : number, c: Array<string>, d : Bar} = {
  a : "hello",
  b : 42,
  c : ["hello", "world"],
  d : new Bar("hello",3)
}

Значение NULL

Любой тип Tnullundefined?TT

 /*@flow*/

var foo : ?string = null;

В этом случае foonull

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

Определения библиотеки

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

К счастью, нам не нужно трогать код библиотеки, чтобы предотвратить эти ошибки. Вместо этого мы можем создать определение библиотеки (libdef). Libdef — это просто причудливый термин для файла JavaScript, который содержит объявления функций или методов, предоставляемых сторонним кодом.

Давайте посмотрим на пример, чтобы лучше понять, что мы обсуждаем:

 /* @flow */

var users = [
  { name: 'John', designation: 'developer' },
  { name: 'Doe', designation: 'designer' }
];

function getDeveloper() {
  return _.findWhere(users, {designation: 'developer'});
}

Этот код выдаст следующую ошибку:

  интерфейсы / app.js: 9 
    9: return _.findWhere (пользователи, {обозначение: 'разработчик'}); 
                ^ идентификатор `_`.  Не удалось разрешить имя 
 

Ошибка генерируется, потому что Flow ничего не знает о переменной _ Чтобы решить эту проблему, нам нужно ввести libdef для Underscore.

Используя типизированный поток

К счастью, существует репозиторий с именем flow-typed, который содержит файлы libdef для многих популярных сторонних библиотек. Чтобы использовать их, вам просто нужно загрузить соответствующее определение в папку с именем flow-typed

Чтобы еще больше упростить процесс, для загрузки и установки файлов libdef доступен инструмент командной строки. Он устанавливается через npm:

 npm install -g flow-typed

После установки запустив flow-typed installpackage.json

Создание пользовательских libdefs

Если используемая вами библиотека не имеет библиотеки libdef, доступной в репозитории с типом потока, можно создать свою собственную. Я не буду вдаваться в подробности, поскольку вам не нужно делать это очень часто, но если вам интересно, вы можете проверить документацию .

Удаление аннотаций типа

Поскольку аннотации типов не являются допустимым синтаксисом JavaScript, нам необходимо удалить их из кода перед его выполнением в браузере. Это можно сделать с помощью инструмента flow-remove-types или в качестве предустановки Babel , если вы уже используете Babel для переноса своего кода. Мы обсудим только первый метод в этой статье.

Во-первых, нам нужно установить flow-remove-types как зависимость проекта:

 npm install --save-dev flow-remove-types

Затем мы можем добавить еще одну запись scriptpackage.json

 "scripts": {
  "flow": "flow",
  "build": "flow-remove-types src/ -D dest/",
}

Эта команда удалит все аннотации типов из файлов, присутствующих в папке srcdist Скомпилированные файлы могут быть загружены в браузер, как и любой другой файл JavaScript.

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

Выводы

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

Как вы относитесь к статической проверке типов для JavaScript? Является ли это чем-то полезным или просто ненужным инструментом, усложняющим современный JavaScript? Эта статья подтолкнула вас к ознакомлению с Flow? Не стесняйтесь поделиться своими мыслями, сомнениями или комментариями ниже.