В моих приложениях React/JavaScript есть три уровня «безопасности» разработки, которые я всегда добавляю:

  1. ESLint, чтобы убедиться, что код соответствует определенному стандарту
  2. Модульное тестирование, чтобы убедиться, что коды можно тестировать
  3. Статическая типизация, чтобы добавить ясности и уменьшить путаницу

В этой статье я расскажу, как начать использовать статическую типизацию с Flow в приложениях React.

Есть несколько технологий, которые мы можем использовать для добавления статической типизации в JavaScript, наиболее популярным из которых является TypeScript (TS). Он разработан Microsoft в 2012 году и имеет большое сообщество. Все основные интерфейсные библиотеки, такие как Angular, Vue и React, поддерживают TS.

Но лично я предпочитаю Flow, а не TS. Flow разработан Facebook в 2014 году. Вот (вероятно, субъективные) причины, по которым мне больше нравится Flow:

  1. Он разработан Facebook (который разработал React, мою любимую библиотеку интерфейса). Поэтому, естественно, React лучше работает с Flow.*
  2. Чтобы сделать JS-файл для использования Flow, я просто добавляю одну строку поверх файла (//@flow). Расширение файла по-прежнему будет .js.
  3. TS — это совершенно новый язык с собственным расширением файла (.ts). В то время как Flow — это скорее инструмент проверки типов, который вы применяете в своих JS-приложениях. Вроде как ESLint imo.
  4. Поскольку TS — совершенно новый язык, у него более высокая кривая обучения.
  5. Гораздо проще преобразовать код JS с помощью Flow обратно в чистый JS.
  6. Вы можете легко интегрировать Flow в существующее приложение JS.
  7. Flow просто проще.

*Однако для приложений Node я больше склоняюсь к TS

На самом деле, если вы напишете файл длиной в 10 000 строк без каких-либо внешних зависимостей, без каких-либо типов. Flow по-прежнему сможет указать вам, где находятся ошибки.
Джеймс Кайл, член команд Babel и Flow.

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

Установка Flow и вспомогательных библиотек

Очевидно, нам сначала нужно установить Flow. И поскольку мы используем Flow в приложении React, которое использует Babel для компиляции, нам также нужно добавить несколько других библиотек.

// install Flow
npm install --save-dev flow-bin
// install Babel support for Flow
npm install --save-dev @babel/preset-flow babel-plugin-transform-flow-strip-types

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

{
  "presets": [
    ...,
    "@babel/preset-flow"
  ],
  "plugins": [
    ...,
    "transform-flow-strip-types"
  ]
}

Запуск Flow-сервера

Прежде чем мы сможем запустить сервер Flow, нам нужно его инициализировать и настроить. Сначала запустите эту команду:

npm run flow init

Эта команда приведет к созданию пустого файла .flowconfig. Это конфигурация, которую я использую в своем примере приложения.

[ignore]
.*/node-modules/.*
[include]
./src
[libs]
[lints]
[options]
react.runtime=automatic
[strict]

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

Чтобы запустить сервер Flow, сначала я добавляю этот скрипт на package.json:

"scripts": {
  ...,
  "flow": "flow",
  "flow-stop": "flow stop"
},

Затем в консоли просто введите npm run flow, чтобы запустить фоновый процесс сервера Flow. Эта команда покажет на консоли все ошибки, связанные со статическим типом; которых на данном этапе, вероятно, нет.

Используйте npm run flow-stop, если вы хотите остановить фоновый процесс сервера Flow.

Добавление поддержки Flow в IDE

Я использую Visual Studio Code от Microsoft в качестве своей IDE, поэтому приведенный ниже пример относится только к этому VSCode.

  1. Установите плагин Flow Language Support от flowtype.
  2. Отключите встроенную поддержку TypeScript в VSCode.

Встроенная поддержка TS может конфликтовать с плагином Flow. Вы можете найти этот плагин, набрав `@builtin TypeScript` на вкладке «Расширения» в VSCode. Как только вы его нашли, отключите плагин.

Проверьте здесь для получения дополнительной информации.

Добавление статической проверки типов Flow

Чтобы добавить поддержку статического типа, просто добавьте этот код в первую строку любого JS-файла:

// @flow

Вот и все!

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

Изучите файл 002-react-flow/src/someMethods.js в примере, чтобы увидеть простой файл JavaScript со статическим типом.

Использование Flow на компонентах React

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

Реагировать Компонент

Нам нужно импортировать тип React, который мы используем, в компонент. Поскольку обычно компонент React возвращает Node, нам нужно убедиться, что он импортирован.

import type {Node} from "react";

Компонент обычно принимает свойства. Допустим, у компонента есть два свойства: foo и bar. В Flow мы определяем эти свойства следующим образом:

type Props = {
  foo: number,
  bar?: string
};

Если компонент использует state, нам также необходимо определить его:

type State = {
  count: number,
};

Затем нам нужно аннотировать эти определения в компоненте:

class SimpleComponent extends Component<Props, State> {
...

И, наконец, в методе render() мы должны добавить аннотацию возвращаемого типа:

render(): Node {
...

Это полный код для этого примера компонента:

// @flow
import type {Node} from "react";
import React, {Component} from 'react';
type Props = {
  foo: number,
  bar?: string,
};
type State = {
  count: number,
};
class SimpleComponent extends Component<Props, State> {
  constructor() {
    super();
  this.state = {
      count: 0,
    }
  }
  componentDidMount() {
    setInterval(() => {
      this.setState(prevState => (
        { count: prevState.count + 1 }
      ));
    }, 1000);
  }
  render(): Node {
    return (
      <div>
        {this.props.foo} {this.props.bar}
        <br/>
        Count: {this.state.count}
      </div>
    );
  }
}
export default SimpleComponent;

Функциональный компонент React

В основном аналогично предыдущему примеру, но с немного другим синтаксисом. Обратите внимание, что здесь мы не расширяем объект Component. И мы объявляем типы свойств в параметре функции.

// @flow
import type {Node} from "react";
import React from 'react';
type Props = {
 text: string,
 addExclamMark: boolean,
};
const SimpleFuncComponent = ({text, addExclamMark}: Props): Node => {
 return (
  <div>
    {`${text}${addExclamMark ? '!' : ''}`}
  </div>
 )
};
export default SimpleFuncComponent;

Вывод

Да, у TS гораздо большее сообщество. Но нет ничего необычного в том, чтобы выбрать технологию, которая лучше подходит вашему стилю/среде разработки. В моем случае Flow оказался лучшим вариантом (при разработке приложений React). Опять же, это субъективное мнение. Возможно, в будущем я передумаю, кто знает. Но на данный момент мне гораздо удобнее использовать Flow. И я знаю некоторые организации, которым удобно вообще не использовать статическую типизацию в своих JS-приложениях.

Наконец, я предоставил полный пример приложения React на своем Github. Если у вас возникли проблемы с прочтением статьи или запуском примера приложения, или у вас есть какие-либо вопросы, пожалуйста, упомяните меня в Твиттере. Ваше здоровье!