7 правил ESLint, рекомендуемых для проектов TypeScript/React

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

GIF: автоматический формат для импорта только типов

Обычно можно настроить ESLint и Prettier на основе пресетов, таких как Airbnb, Google и Standard. Но если эти пресеты не подходят для вашего проекта, не расстраивайтесь: у вас все еще есть возможности для оптимизации.

Вот 7 рекомендуемых конфигураций ESLint, которые значительно улучшат ваш проект TypeScript/React.

1. arrow-body-style

Очень простое правило arrow-body-style способно устранить множество проблем при написании кода. Рекомендуемая его настройка  —  "arrow-body-style": ["error", "as-needed"]  —  приводит к удалению ненужного возврата, как показано ниже.

// "arrow-body-style": ["error", "as-needed"],

// Неверно
let foo = () => {
    return 0;
};

// Верно
let foo = () => 0
GIF: автоформат для arrow-body-style

2. react/self-closing-comp

Правило react/self-closing-comp схоже с arrow-body-style. Несмотря на свою простоту, оно существенно экономит время, выполняя автоматическое закрытие тегов в JSX.

Рекомендуемая настройка  —  react/self-closing-comp: ["error", { "component": true, "html": true }].

// "react/self-closing-comp": [
//   "error", { 
//     "component": true,
//     "html": true
//   }
// ]

// Неверно
<Hello name="John"></Hello>;
<div className="content"></div>;

// Верно
<Hello name="John" />
<div className="content" />

"component": true приводит к написанию пользовательского компонента с автоматически закрывающимся тегом. Кроме того, "html": true изменяет обычный html-тег на самозакрывающийся.

GIF: автоформат для компонента с самозакрывающимся тегом

3. autofix/no-unused-vars

Это производное из ESLint-правила no-unused-vars. Поскольку оригинальная настройка no-unused-vars не производит форматирование автоматически, стоит использовать eslint-plugin-autofix.

$ yarn add -D eslint-plugin-autofix

После этого добавьте его как плагин ESLint.

{
"plugins": ["react", "@typescript-eslint", "autofix"],
"rules": {
...
}
}

Теперь можно использовать установленное правило no-unused-vars, как показано ниже!

// "autofix/no-unused-vars": [
//   "error",
//   {
//     "argsIgnorePattern": "^_",
//     "ignoreRestSiblings": true,
//     "destructuredArrayIgnorePattern": "^_"
//   }
//  ]

// Неверно
function foo(x, y) {
    return x + 1;
}
foo();

var { foo, ...coords } = data;

const [a, b] = ["a", "b"];
console.log(b);

// Верно
function foo(x, _y) {
    return x + 1;
}
foo();

var { foo, ...coords } = data;

const [_a, b] = ["a", "b"];
console.log(b);

Если просто добавить autofix/no-used-vars: "error", то все неиспользуемые переменные покажут ошибку, выданную контролем качества кода. Однако иногда нужно определить неиспользуемые переменные для демонстрации определенных намерений. Поэтому рекомендую использовать argsIgnorePattern: "^_" . С префиксом _ это разрешено.

ignoreRestSiblings-опция destructuredArrayIgnorePattern  —  это правила, специфичные для каждого конкретного случая.

Иногда ключ удаляется из объекта с применением свойства REST, как показано ниже. В этой ситуации можно больше не использовать удаленный ключ. Игнорировать его позволит ignoreRestSiblings.

const obj = { first: "John", last: "Lennon", age: 30 };
const { age, ...name } = obj;  // remove age from obj

// => ошибка ESLint в отношении age не возникает. 

Аналогичная ошибка ESLint возникает при деструктурировании массива. В этом случае можно не использовать первый деструктурированный элемент. Предотвратить ошибку ESLint позволит destructuredArrayIgnorePattern: "^_".

const [_A, B, C] = Promise.all([fetchA, fetchB, fetchC]);

console.log(B, C);

// => ошибка ESLint в отношении A не возникает. 

4. @typescript-eslint/consistent-type-imports

При импортировании типов TypeScript рекомендуется использовать функцию импорт только для типов для повышения производительности. Но меня волнует правильное использование обычного импорта и только для типов.

import { useEffect } from "react;
import type { FC } from "react;

Поэтому пришло время использовать @typescript-eslint/consistent-type-imports. Это правило автоматически определяет, является ли импортируемый модуль типом или нет, и при необходимости форматирует его.

// "@typescript-eslint/consistent-type-imports": [
//   "error",
//   {
//     "prefer": "type-imports",
//   }   
// ],

// Неверно
import { useEffect, FC } from "react";

// Верно
import { useEffect } from "react";
import type { FC } from "react";
GIF: автоформат для импорта только типов

5. import/order

На самом деле правило import/order мне нравится больше всего. Поскольку импортов очень много, организация порядка импорта вручную занимает в общей сложности много времени. Поэтому пришло время использовать автоформат!

// "import/order": [
// "error",
// {
// "groups": [
// "builtin",
// "external",
// "parent",
// "sibling",
// "index",
// "object",
// "type"
// ],
// "pathGroups": [
// {
// "pattern": "@/**/**",
// "group": "parent",
// "position": "before"
// }
// ],
// "alphabetize": { "order": "asc" }
// }
// ],

Само правило довольно сложное. Ключ groups определяет фактический порядок между типами модулей. Приведенная выше конфигурация располагает узел, встроенный в модули (например, path), перед внешними пакетами (например, react). Если хотите узнать подробности о каждой группе, ознакомьтесь с официальной документацией.

pathGroups создает пользовательскую группу. Я часто определяю ее для импорта псевдонимов.

// импорт псевдонимов
import foo from "../../src/path/to/foo"; // not readable
import foo from "@/src/path/to/foo"; // using import alias

С настройкой pathGroups модули, использующие импорт псевдонимов, упорядочиваются перед parent.

alphabetize означает порядок в одном модуле. react упорядочивается перед vue (конечно, так не бывает).

6. no-restricted-imports

Как уже было сказано выше, импорт псевдонимов очень полезен. После введения импорта псевдонимов вам, возможно, понадобится запретить использование относительного импорта. Поэтому пришло время установить no-restricted-imports.

// "no-restricted-imports": [
// "error",
// {
// "patterns": ["../"]
// }
// ],

Это правило ограничивает импорт родительского модуля по относительному пути. С другой стороны, оно позволяет импортировать дочерний модуль по относительному пути. Это своего рода предпочтение. Чтобы запретить любой относительный путь, нужно просто добавить ./ к patterns.

На самом деле это не форматируется автоматически, потому что ESLint не знает пользовательский импорт псевдонимов. Поэтому выполнение осуществляется вручную.

7. react-hooks/exhaustive-deps

React-хук требует определения зависимостей, чтобы установить, когда должна быть запущена внутренняя логика. Но если у вас сложная логика в React-хуке, трудно точно прописать все зависимости. Поэтому для обнаружения недостающих зависимостей стоит использовать react-hooks/exhaustive-deps.

Для применения правила ESLint react-hooks нужно установить пакет react-hooks в качестве плагина.

// .eslintrcjson
{
"plugins": [
"react",
"@typescript-eslint",
"autofix",
"react-hooks"
],
}

Само правило очень простое. Просто добавьте одну строку, как показано ниже.

// "react-hooks/exhaustive-deps": "error"
Изображение: exhaustive-deps error

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Toru Eguchi: 7 Recommended ESLint Rules for React TypeScript Project

Предыдущая статьяСоздаем первый «Astroвной» проект
Следующая статьяМониторинг кластера Kubernetes без зависимостей