Spec-Zone.ru › Flow

Справочник по правилам lint

all​

Хотя all технически не является правилом lint, здесь стоит упомянуть о нём. all задаёт уровень по умолчанию для правил lint, для которых уровень не задан явно. all может встречаться только первой записью в .flowconfig или первым правилом во флаге --lints. В комментариях он не допускается, поскольку его семантика отличалась бы от ожидаемой.

ambiguous-object-type​

Срабатывает, если используется синтаксис типа object без явного указания точности или неточности.

Эта настройка lint игнорируется, если для exact_by_default задано значение false.

// flowlint ambiguous-object-type:error


type A = {x: number}; // Error
type B = {x: number, ...} // Ok
type C = {| x: number |} // Ok

deprecated-type​

Срабатывает при использовании типа bool, который является всего лишь псевдонимом для boolean. Вместо него используйте boolean.

// flowlint deprecated-type:error


type A = Array<bool>; // Error

nested-component​

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

По умолчанию это правило lint включено с уровнем ошибки. Оно применяется к объявлениям с помощью синтаксиса компонентов, для которых в .flowconfig требуется component_syntax=true.

import * as React from 'react';


component Outer() {
  component Inner() { // Error
    return null;
  }
  return <Inner />;
}

Правило lint также срабатывает, если компонент определён внутри хука:

import * as React from 'react';


hook useItems() {
  component ItemView() { // Error
    return null;
  }
  return ItemView;
}

Чтобы исправить это, перенесите вложенный компонент на верхний уровень:

import * as React from 'react';


component Inner() {
  return null;
}


component Outer() {
  return <Inner />;
}

nested-hook​

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

По умолчанию это правило lint включено с уровнем ошибки. Оно применяется к объявлениям с помощью синтаксиса хуков, для которых в .flowconfig требуется component_syntax=true.

import * as React from 'react';
import {useState} from 'react';


component Foo() {
  hook useNested() { // Error
    return useState();
  }
  return null;
}

Правило lint также срабатывает, если хук определён внутри другого хука:

import {useState} from 'react';


hook useFoo() {
  hook useNested() { // Error
    return useState();
  }
  return useNested();
}

Чтобы исправить это, перенесите вложенный хук на верхний уровень:

import * as React from 'react';
import {useState} from 'react';


hook useNested() {
  return useState();
}


component Foo() {
  useNested();
  return null;
}

libdef-override​

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

По умолчанию это правило lint включено с уровнем ошибки.

У этой ошибки есть две разновидности. Первая — переопределение имени; она возникает, когда определение библиотеки повторно объявляет уже существующую глобальную переменную или тип:

// In a library definition file (.js.flow or [libs])
declare const globalThis: mixed; // Error: overrides built-in globalThis

declare type React$Node = string; // Error: overrides built-in React$Node

Вторая — переопределение модуля; она возникает, когда определение библиотеки повторно объявляет модуль, уже объявленный в другом месте:

// In a library definition file
declare module 'react' { // Error: overrides built-in react module
  declare module.exports: any;
}

Эта ошибка также возникает, если один и тот же файл библиотеки включён дважды (например, если в разделе [libs] файла .flowconfig указаны и каталог, и его подкаталог), из-за чего все объявления в этом файле конфликтуют сами с собой.

Чтобы исправить ошибку, удалите из определения библиотеки избыточное объявление. Если вам намеренно нужно переопределить встроенное определение, ошибку можно подавить комментарием $FlowFixMe:

// $FlowFixMe[libdef-override]
declare type React$Node = string | number | null;

Также это правило lint можно отключить для всего проекта в файле .flowconfig:

[lints]
libdef-override=off

internal-type​

Срабатывает, если внутренний тип Flow используется непосредственно в коде. Внутренние типы — это детали реализации, для которых существуют общедоступные альтернативы; вместо них следует использовать эти альтернативы.

По умолчанию это правило lint включено с уровнем ошибки.

Это правило lint срабатывает для двух категорий внутренних типов:

Вспомогательные типы с префиксом доллара, такие как $Omit, $Enum и $EnumValue, имеют варианты без доллара (Omit, Enum, EnumValue):

type A = $Omit<{x: number, y: number}, 'x'>; // Error
type B = Omit<{x: number, y: number}, 'x'>; // Ok

Типы React$, такие как React$Node и React$ElementConfig, следует использовать через пространство имён React с помощью точечной нотации (React.Node, React.ElementConfig):

import * as React from 'react';


type A = React$Node; // Error
type B = React.Node; // Ok

invalid-this-arg​

Срабатывает, если call, apply или bind используется, чтобы задать методу получателя, отличного от того, у которого этот метод был получен. Повторная привязка метода, у которого this зависит от получателя, приводит к выполнению его тела для объекта, для которого он не предназначался; в иерархии классов это небезопасно — объяснение см. в разделе Повторная привязка this. Допустимы формы obj.method.call(obj, ...) и this.method.bind(this).

По умолчанию это правило lint включено с уровнем ошибки.

type Counter = {
  count: number,
  increment(this: Counter): number,
};


declare const counter: Counter;
declare const other: Counter;


counter.increment.call(counter); // Ok
counter.increment.call(other); // Error

Метод, принимающий любого получателя (this: unknown, this: any или без аннотации this и без использования this в теле), не ограничивается этим правилом. Оно также не затрагивает член call/apply/bind, который разрешается относительно самого получателя, а не Function.prototype.

nonstrict-import​

Используется вместе с Flow Strict. Срабатывает при импорте модуля, не являющегося @flow strict. Если правило включено, зависимости модуля @flow strict также должны быть @flow strict.

react-intrinsic-overlap​

Срабатывает, если локальное определение имеет то же имя, что и встроенный элемент JSX (например, div, span или input), и его тип может использоваться как компонент React. Поскольку JSX трактует имена элементов в нижнем регистре как встроенные, запись <div /> всегда ссылается на элемент HTML, а не на локальное связывание с именем div. Если локальное связывание — это функция, класс, абстрактный компонент, вызываемый объект или mixed, такое совпадение, скорее всего, является ошибкой и приводит к запутанному поведению.

По умолчанию это правило lint отключено.

Локальная функция, имя которой совпадает с именем встроенного элемента:

// flowlint react-intrinsic-overlap:error
import * as React from 'react';


declare function div(): React.Node; // ERROR
<div />;

Локальная переменная с типом, который не является типом компонента, не вызывает это правило lint, поскольку неоднозначности нет:

// flowlint react-intrinsic-overlap:error
import * as React from 'react';


const div = 2 / 3;
<div />; // OK

Чтобы исправить ошибку, переименуйте локальное определение так, чтобы его имя не совпадало с именем встроенного элемента:

// flowlint react-intrinsic-overlap:error
import * as React from 'react';


declare function MyDiv(): React.Node;
<MyDiv />;

sketchy-null​

Срабатывает при проверке существования значения, которое может быть null/undefined или ложным.

Например:

// flowlint sketchy-null:error


const x: ?number = 5;
if (x) {} // Error: sketchy because x could be either null or 0.


const y: number = 5;
if (y) {} // not sketchy because y can't be null, only 0.


const z: ?{foo: number} = {foo: 5};
if (z) {} // not sketchy, because z can't be falsey, only null/undefined.

Настройка sketchy-null задаёт уровень для всех проверок на сомнительное значение null, но для отдельных типов есть более точечные правила. Это:

  • sketchy-null-bool
  • sketchy-null-number
  • sketchy-null-string
  • sketchy-null-mixed
  • sketchy-null-bigint

Варианты для конкретных типов полезны, когда нужно указать, что одни проверки на сомнительное значение null допустимы, а другие должны приводить к ошибкам или предупреждениям. Например, если вы хотите разрешить такие проверки для логических значений (чтобы трактовать неопределённые необязательные логические значения как false), но запретить их для других типов, это можно сделать в разделе .flowconfig [lints]:

[lints]
sketchy-null=warn
sketchy-null-bool=off

и теперь

function foo (bar: ?boolean): void {
  if (bar) {
    ...
  } else {
    ...
  }
}

не выдаёт предупреждение.

Подавление проверки на сомнительное значение null для одного типа подавляет только проверки этого типа. Например,

// flowlint sketchy-null:error, sketchy-null-bool:off
const x: ?(number | boolean) = 0;
if (x) {} // Error

всё равно приведёт к ошибке sketchy-null-number в строке 3.

sketchy-number​

Срабатывает, если number используется способом, который может привести к неожиданным результатам, если значение ложно. В настоящее время это правило lint срабатывает, если number находится:

  • в левой части выражения &&.

В качестве примера рассмотрим распространённый идиоматический приём в React:

{showFoo && <Foo />}

Здесь showFoo — логическое значение, которое определяет, отображать ли элемент <Foo />. Если showFoo равно true, выражение вычисляется в {<Foo />}. Если showFoo равно false, выражение вычисляется в {false}, и ничего не отображается.

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

{count && <>[{count} comments]</>}

Если count равно, например, 5, отобразится «[5 comments]». Однако, если count равно 0, отобразится «0», а не пустое место. (Эта проблема характерна только для number, потому что 0 и NaN — единственные ложные значения, которые React отображает видимым образом.) Это может незаметно привести к проблемам: если такое значение идёт сразу после другого числа, пользователю может показаться, что это число умножили на 10! Вместо этого следует выполнить корректную условную проверку:

{count ? <>[{count} comments]</> : null}

unclear-type​

Срабатывает, если any, Object или Function используется в качестве аннотации типа. Эти типы небезопасны.

// flowlint unclear-type:error


declare const a: any; // Error
declare const c: Object; // Error
declare const d: Function; // Error

unnecessary-invariant​

Срабатывает, если invariant используется для проверки условия, которое, согласно доступной информации о типах, заведомо должно быть истинным. Проверка довольно консервативна: например, если всё, что нам известно об условии, — это то, что оно имеет тип boolean, правило lint не сработает, даже если во время выполнения условие обязательно будет true.

Обратите внимание: это правило lint не срабатывает, если известно, что условие всегда false. Часто для выброса исключения в коде, который не должен выполняться, используют invariant() или invariant(false, ...).

// flowlint unnecessary-invariant:error
declare function invariant(boolean): void;


declare const x: Array<string>; // Array is truthy
invariant(x); // Error

unnecessary-optional-chain​

Срабатывает при использовании ?., когда в нём нет необходимости. Есть два основных случая. Первый — когда левая часть не может быть nullish:

// flowlint unnecessary-optional-chain:error
type Foo = {
  bar: number
}


declare const foo: Foo;
foo?.bar; // Error

Второй — когда левая часть может быть nullish, но для обработки этого достаточно поведения короткого замыкания оператора ?.:

// flowlint unnecessary-optional-chain:error
type Foo = {
  bar: {
    baz: number
  }
}


declare const foo: ?Foo;
foo?.bar?.baz; // Error

Во втором примере первое использование ?. допустимо, поскольку foo потенциально может быть nullish, а второе использование ?. избыточно. Левая часть второго ?. (foo?.bar) может быть nullish только в результате того, что foo является nullish. Когда foo является nullish, короткое замыкание позволяет вообще не выполнять второе ?.!

foo?.bar.baz;

Так читателю ясно, что bar не является свойством, которое потенциально может быть nullish.

unsafe-getters-setters​

Срабатывает при использовании геттеров или сеттеров. Геттеры и сеттеры могут иметь побочные эффекты и небезопасны.

Например:

// flowlint unsafe-getters-setters:error
let a = 1;
const o = {
  get a() { return a; }, // Error: unsafe-getters-setters
  set b(x: number) { a = x; }, // Error: unsafe-getters-setters
  c: 10,
};

unsafe-object-assign​

Срабатывает при любом использовании Object.assign. Поддержка Object.assign в Flow небезопасна; вместо этого следует использовать spread-синтаксис объектов.

По умолчанию это правило lint включено с уровнем ошибки.

Object.assign изменяет первый аргумент на месте, что затрудняет отслеживание изменений в системе типов. Spread-синтаксис ({...obj1, ...obj2}) — более безопасная альтернатива: он всегда создаёт новый объект, тип которого Flow может точно определить.

const defaults = {color: 'red', size: 10};
const overrides = {color: 'blue'};


const config = Object.assign(defaults, overrides); // Error

Вместо этого используйте spread-синтаксис:

const defaults = {color: 'red', size: 10};
const overrides = {color: 'blue'};


const config = {...defaults, ...overrides}; // Ok

untyped-import​

Срабатывает при импорте из нетипизированного файла. В результате импорта из нетипизированного файла импортируемым значениям назначается тип any, что небезопасно.

untyped-type-import​

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

unused-promise​

Срабатывает, если Promise не используется. Это может быть опасно: ошибки могут остаться необработанными, а код может выполниться в нежелательном порядке.

Промис можно считать «использованным», если...

  • await (обработать его)
  • вызвать .then с обработчиком отклонения (то есть с двумя аргументами)
  • вызвать .catch
  • вызвать .finally
  • сохранить его в переменной, передать функции и т. д.

Например:

// flowlint unused-promise:error
declare function foo(): Promise<void>;


async function bar() {
  await foo(); // ok
  foo(); // error, we forgot to await!
}


function baz() {
  foo().catch(err => {console.log(err)}); // ok
  foo(); // error
}

Можно явно проигнорировать промис с помощью оператора void (например, void foo();).

См. также​

  • Комментарии Flowlint — управление серьёзностью правил lint внутри файла с помощью комментариев
  • .flowconfig [lints] — настройка серьёзности правил lint для всего проекта
  • Правила lint для строгого импорта и экспорта ES6 — дополнительные правила lint для выявления небезопасных шаблонов импорта и экспорта ES6
  • Flow Strict — более строгая проверка типов, включающая дополнительные правила, похожие на lint

© 2013–present Facebook Inc.
Licensed under the MIT License.
https://flow.org/en/docs/linting/rule-reference

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API