Справочник по правилам 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-boolsketchy-null-numbersketchy-null-stringsketchy-null-mixedsketchy-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