はじめに
ESLintのバージョン9.0.0からFlat Configという設定ファイルの新たな記法がデフォルトで有効になり、元の記法が非推奨となります。そしてバージョン10.0.0では元の記法がサポートされなくなります。
サポートが切れるため元の記法で記述していた場合はFlat Configへ書き直す必要があります。しかし、同じ設定を記述するには記法が大きく変化したため慣れや工夫が必要となります。
この記事ではFlat Configに移行することへ慣れるための練習として、create-remix
で生成されるremixのESLintの設定をFlat Configに書き直します。
remixの設定はReactを開発する上で一般的なルールが記載されているのでeslint-config-next
のような設定がまとまったパッケージを使っていない多くの環境にとって参考になると考えています。
成果物はGitHubで公開しています。
Flat Configについての背景や設定について正確に知りたい場合はこれらのサイトを閲覧することがおすすめです。
移行前の環境準備
まずはcreate-remix
でremixの環境を作成します。
npx create-remix@latest
以下がremixのバージョン2.8.1におけるESLintの設定です。
/**
* This is intended to be a basic starting point for linting in your app.
* It relies on recommended configs out of the box for simplicity, but you can
* and should modify this configuration to best suit your team's needs.
*/
/** @type {import('eslint').Linter.Config} */
module.exports = {
root: true,
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
env: {
browser: true,
commonjs: true,
es6: true,
},
// Base config
extends: ["eslint:recommended"],
overrides: [
// React
{
files: ["**/*.{js,jsx,ts,tsx}"],
plugins: ["react", "jsx-a11y"],
extends: [
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"plugin:jsx-a11y/recommended",
],
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
"import/resolver": {
typescript: {},
},
},
},
// Typescript
{
files: ["**/*.{ts,tsx}"],
plugins: ["@typescript-eslint", "import"],
parser: "@typescript-eslint/parser",
settings: {
"import/internal-regex": "^~/",
"import/resolver": {
node: {
extensions: [".ts", ".tsx"],
},
typescript: {
alwaysTryTypes: true,
},
},
},
extends: [
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
],
},
// Node
{
files: [".eslintrc.cjs"],
env: {
node: true,
},
},
],
};
ESLintの実行はnpm run lint
で実行できます。package.json
のscripts
を確認するとnpx eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .
で実行されていることがわかります。
Flat Configへの移行
create-remix
で生成された.eslintrc.cjs
を元にeslint.config.js
を記述します。remixのパッケージではデフォルトがESMとなっているためESM形式を用います(package.json
でtype
がmodule
になっていない場合は拡張子をmjs
にした方が良いかもしれません)。
テストファイルを作る
Flat Configへ移行した後に設定が有効になっていることを確かめるため以下のようなファイルを作成します。
import { Link, NavLink } from "@remix-run/react";
import { useEffect } from "react";
// violate eslint recommendation
for (let i = 0; i < 10; i--) {
console.log(i);
}
// violate react recommendation
() => {
return <>{
[1, 2, 3].map((i) => <div>{i}</div>)
}</>;
};
// violate react-hooks recommendation
const _ = () => {
const flag = true;
if (flag) {
useEffect(() => {
console.log('effect');
}, []);
}
return <div />;
};
_;
// violate jsx-a11y recommendation
const App = () => {
return (
<>
<a>Link</a>
<Link to="/about">About</Link>
<NavLink to="/contact">Contact</NavLink>
</>
);
};
// violate typescript-eslint recommendation
Array(0, 1, 2);
eslint.config.js
を作成する前にnpm run lint
を実行して、それぞれ異なるパッケージからのエラーが5つ出ることを確認していください。
このファイルはエラーが発生することを確認するために作っただけなので、他のファイルを適当に準備しても問題ありません。
このファイルは移行前後で設定が同一であることを保証するものではないです。それぞれの代表的なルールが有効であることを確かめるために記述していますので、厳密にやりたい場合は他の方法を検討してください。
ESLint Config Inspectorでは有効なルールを可視化してくれるのでおすすめです(記事)。
設定ファイルを作る
eslint.config.js
ファイルを作ります。中身は以下のように記述してください。
/**
* @type {import('eslint').Linter.FlatConfig[]}
*/
export default [];
作成したらESLintは.eslintrc.cjs
ではなくeslint.config.js
を設定ファイルとして読みにいきます。npx eslint --debug
を実行してLoading config from /xxx/eslint.config.js
と表示されることを確認してください。
Flat Configでは設定を有効するファイル単位ごとや、複数の設定を同時に記述するために配列で設定を記述します。
無視するファイル
前の記法では無視するファイルをcliで--ignore-path .gitignore
のように渡していました。Flat Configでは無視するファイルを設定ファイルに記述します。
以下のようにignores
に無視するファイルの一覧を詰め込んで配列に流し込むことで無効化されます。
/**
* @type {import('eslint').Linter.FlatConfig[]}
*/
export default [
{
ignores: ['node_modules', '.cache', 'build', 'public/build', '.env'],
},
];
配列に記述された設定は最終的にマージされて1つの設定ファイルとなるので、これによってignores
に記述したファイルに対して実行されなくなります。
package.json
のscripts
からも--ignore-path
が不要になったので消します。
"lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
Base(プロジェクト全体の設定)
元ファイルのコメントに合わせてBase
、React
、TypeScript
、Node
に分けて移行します。
まずはBase
です。Base
は特別にコメントの範囲を超えてoverrides
以外の全ての設定を記述します。
root
root: true,
前の記法は実行されるファイルからルートのまでのすべての設定ファイルを読み込んでいましたが、Flat Configは最も近い祖先のファイルだけを読み込むのでルートファイルという概念がなくなりroot: true
の宣言自体が不要になりました。
parserOptions
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
ecmaVersion
とsourceType
はparser
だけではなく構成等にも反映するためlanguageOptions
へ書かれるようになり、parserOptions
自体もlanguageOptions
へ記述されるようになりました。
{
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parserOptions: {
ecmaFeatures: {
jsx: true
},
},
},
},
env
env: {
browser: true,
commonjs: true,
es6: true,
},
Flat Configではenv
を削除して、languageOptions
のglobals
に記述するようになりました。そして、globals
パッケージを利用して環境の情報をよりわかりやすく提供するようになりました(globals.jsonに環境ごとの設定が列挙されており、それを展開しています)。
import globals from 'globals';
...
...
{
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
...globals.commonjs,
...globals.es6,
},
parserOptions: {
ecmaFeatures: {
jsx: true
},
},
},
},
globals
パッケージはeslint
をインストールした時の依存パッケージとしてインストールされているのでそのままでも利用出来ますが、直接インポートするのでdevDependencies
に追加した方が良いです。
npm install --save-dev globals
筆者の環境では@remix-run/dev
に依存する@babel/traverse
が古いglobals
を利用しているのでインストールしなければ動きませんでした。
eslint recommended
// Base config
extends: ["eslint:recommended"],
eslint
は当然のことながらFlat Configに対応しているのでドキュメント通りに実装すれば良いです。
@eslint/js
からすでに定義済みの設定を持ってきて先ほどまで記述していた箇所に展開します。定義された内容はeslintのGitHubから確認できます。rules
を記述しているだけだったので、languageOptions
は上書きするような形で配置しました。
import globals from 'globals';
import eslint from '@eslint/js';
...
...
{
...eslint.configs.recommended,
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
...globals.commonjs,
...globals.es6,
},
parserOptions: {
ecmaFeatures: {
jsx: true
},
},
},
},
まとめ
ここまでの移行で設定ファイルは以下のようになりました。
import globals from 'globals';
import eslint from '@eslint/js';
/**
* @type {import('eslint').Linter.FlatConfig[]}
*/
export default tseslint.config(
{
ignores: ['node_modules', '.cache', 'build', 'public/build', '.env'],
},
{
...eslint.configs.recommended,
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
...globals.commonjs,
...globals.es6,
},
parserOptions: {
ecmaFeatures: {
jsx: true
},
},
},
},
);
npx eslint . --debug
で関係ないファイルが実行対象になっていないこと、エラー確認用のコードから期待したエラーが返ることを確認できます。
React
次にReact
です。eslint-plugin-react
、eslint-plugin-react-hooks
、eslint-plugin-jsx-a11y
等の設定をします。
.eslintrc.cjs
ではoverrides
を用いて特定のファイルに対するルールを記述していましたが、Flat Configでは他のルールと同じように配列に追加して、設定内のfiles
によって実行対象のファイルを制限します。
/**
* @type {import('eslint').Linter.FlatConfig[]}
*/
export default tseslint.config(
{
...
},
{
...
},
{
files: ["**/*.{js,jsx,ts,tsx}"],
...
},
);
eslint-plugin-react
eslint-plugin-react
はREADMEのFalt Configのサポートについてを参考に実装します。
eslint-plugin-react
に関連する部分を.eslintrc.cjs
から抜き出すと以下のようになります(今後部分ごとに参照する場合は対象の箇所を抜き出した状態で紹介します)。
// React
{
files: ["**/*.{js,jsx,ts,tsx}"],
plugins: ["react"],
extends: [
"plugin:react/recommended",
"plugin:react/jsx-runtime",
],
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
},
},
settings
はこれまで通り記述できるので、recommended
とjsx-runtime
の箇所を書き換えるだけです。
import reactRecommended from 'eslint-plugin-react/configs/recommended.js';
import reactJSXRuntime from 'eslint-plugin-react/configs/jsx-runtime.js';
...
...
{
files: ['**/*.{js,jsx,ts,tsx}'],
...reactRecommended,
...reactJSXRuntime,
rules: {
...reactRecommended.rules,
...reactJSXRuntime.rules,
},
languageOptions: {
...reactRecommended.languageOptions,
...reactJSXRuntime.languageOptions,
},
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
},
},
recommended
とjsx-runtime
に実装された内容を元にしてそれぞれ展開しています。React17以降のJSXの変換へ対応するためにrecommended
のルールをjsx-runtime
のルールで上書きして欲しいのでjsx-runtime
の方を後から宣言しました。
rules
の内容をそれぞれ確認するとrecommended
の方は'react/react-in-jsx-scope': 2
に対してjsx-runtime
では'react/react-in-jsx-scope': 0
となっていてこの記述では0
が有効になります。
eslint-plugin-react-hooks
eslint-plugin-react
とは異なり、パッケージ自体でFlat Confingの対応が行われていないのでFlat Configで扱えるように変換する必要があります。
このように対応されていないパッケージとの互換性のためにFlatCompat
というクラスが準備されています(使い方についてのブログ)。
// React
{
files: ["**/*.{js,jsx,ts,tsx}"],
extends: [
"plugin:react-hooks/recommended",
],
},
new FlatCompat()
で生成したcompat
を元にeslint-plugin-react-hooks
のrecommended
をFlat Configで利用できるように最適化します。
import { FlatCompat } from '@eslint/eslintrc';
import reactRecommended from 'eslint-plugin-react/configs/recommended.js';
import reactJSXRuntime from 'eslint-plugin-react/configs/jsx-runtime.js';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
...
const compat = new FlatCompat();
...
{
files: ["**/*.{js,jsx,ts,tsx}"],
...reactRecommended,
...reactJSXRuntime,
rules: {
...reactRecommended.rules,
...reactJSXRuntime.rules,
},
languageOptions: {
...reactRecommended.languageOptions,
...reactJSXRuntime.languageOptions,
},
extends: [
...compat.config(reactHooksPlugin.configs.recommended),
],
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
},
},
eslint-plugin-jsx-a11y
このライブラリもeslint-plugin-react-hooks
と同じくFlat Configの対応が完了しておりません。
// React
{
files: ["**/*.{js,jsx,ts,tsx}"],
plugins: ["jsx-a11y"],
extends: [
"plugin:jsx-a11y/recommended",
],
},
先ほどと異なる点はplugins
があることです。plugins
は対応するパッケージに対応させるように宣言します。
import { FlatCompat } from '@eslint/eslintrc';
import reactRecommended from 'eslint-plugin-react/configs/recommended.js';
import reactJSXRuntime from 'eslint-plugin-react/configs/jsx-runtime.js';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
...
const compat = new FlatCompat();
...
{
files: ["**/*.{js,jsx,ts,tsx}"],
...reactRecommended,
...reactJSXRuntime,
rules: {
...reactRecommended.rules,
...reactJSXRuntime.rules,
},
languageOptions: {
...reactRecommended.languageOptions,
...reactJSXRuntime.languageOptions,
},
plugins: {
['jsx-a11y']: jsxA11yPlugin,
},
extends: [
...compat.config(reactHooksPlugin.configs.recommended),
...compat.config(jsxA11yPlugin.configs.recommended),
],
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
},
},
まとめ
対応していないsettings
の"import/resolver"
を新しいファイルに移した段階でのファイルは以下のようになっています。
import globals from 'globals';
import eslint from '@eslint/js';
import { FlatCompat } from '@eslint/eslintrc';
import reactRecommended from 'eslint-plugin-react/configs/recommended.js';
import reactJSXRuntime from 'eslint-plugin-react/configs/jsx-runtime.js';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
const compat = new FlatCompat();
/**
* @type {import('eslint').Linter.FlatConfig[]}
*/
export default tseslint.config(
{
ignores: ['node_modules', '.cache', 'build', 'public/build', '.env'],
},
{
...eslint.configs.recommended,
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
...globals.commonjs,
...globals.es6,
},
parserOptions: {
ecmaFeatures: {
jsx: true
},
},
},
},
{
files: ["**/*.{js,jsx,ts,tsx}"],
...reactRecommended,
...reactJSXRuntime,
rules: {
...reactRecommended.rules,
...reactJSXRuntime.rules,
},
languageOptions: {
...reactRecommended.languageOptions,
...reactJSXRuntime.languageOptions,
},
plugins: {
['jsx-a11y']: jsxA11yPlugin,
},
extends: [
...compat.config(reactHooksPlugin.configs.recommended),
...compat.config(jsxA11yPlugin.configs.recommended),
],
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
"import/resolver": {
typescript: {},
},
},
},
);
Typescript
続いてTypeScript
です。typescript-eslint
とeslint-plugin-import
の対応です。
まずはTypeScriptのファイルに対してルールを記述する場所を作ります。
/**
* @type {import('eslint').Linter.FlatConfig[]}
*/
export default tseslint.config(
{
...
},
{
...
},
{
...
},
{
files: ["**/*.{ts,tsx}"],
...
},
);
eslint-plugin-import
eslint-plugin-react-hooks
と同じようにFlatCompat
を利用して移行します。
{
files: ["**/*.{ts,tsx}"],
plugins: ["import"],
settings: {
"import/internal-regex": "^~/",
"import/resolver": {
node: {
extensions: [".ts", ".tsx"],
},
typescript: {
alwaysTryTypes: true,
},
},
},
extends: [
"plugin:import/recommended",
"plugin:import/typescript",
],
},
settings
はそのまま移行して、plguins
とextends
はパッケージをインポートして記述します。
import importPlugin from 'eslint-plugin-import';
...
...
{
files: ["**/*.{ts,tsx}"],
plugins: {
import: importPlugin,
},
extends: [
...compat.config(importPlugin.configs.recommended),
...compat.config(importPlugin.configs.typescript),
],
settings: {
"import/internal-regex": "^~/",
"import/resolver": {
node: {
extensions: [".ts", ".tsx"],
},
typescript: {
alwaysTryTypes: true,
},
},
},
},
typescript-eslint
typescript-eslint
はFlat Configのサポートがされており、リリースブログを元に移行します。
まずは、利用するパッケージが変更されたのでこれまでの@typescript-eslint/parser
と@typescript-eslint/eslint-plugin
をアンインストールしてtypescript-eslint
を導入します。
npm uninstall @typescript-eslint/parser @typescript-eslint/eslint-plugin
npm install --save-dev typescript-eslint
そして、これまで記述してきたESLintの設定全体をtseslint.config
で囲みます。配列は展開して関数の引数に渡します。
import tseslint from 'typescript-eslint';
...
...
export default tseslint.config(
{
...
},
{
...
},
{
...
},
{
...
},
);
これによって設定ファイル内の型やエディターの補完を強化してくれます。記述しなくても動きますが、typescript-eslint
では利用することを強く推奨しています。
typescript-eslint
を利用する準備ができたので移行します。
{
files: ["**/*.{ts,tsx}"],
plugins: ["@typescript-eslint"],
parser: "@typescript-eslint/parser",
extends: [
"plugin:@typescript-eslint/recommended",
],
},
プラグインやパーサー等は自動で解決してくれるため不要です。extends
にimport
と合わせて記述します。
import tseslint from 'typescript-eslint';
import importPlugin from 'eslint-plugin-import';
...
...
{
files: ["**/*.{ts,tsx}"],
plugins: {
import: importPlugin,
},
extends: [
...tseslint.configs.recommended,
...compat.config(importPlugin.configs.recommended),
...compat.config(importPlugin.configs.typescript),
],
settings: {
"import/internal-regex": "^~/",
"import/resolver": {
node: {
extensions: [".ts", ".tsx"],
},
typescript: {
alwaysTryTypes: true,
},
},
},
},
まとめ
tslint.config
が加わって全体的な変化が加わりました。
import globals from 'globals';
import eslint from '@eslint/js';
import { FlatCompat } from '@eslint/eslintrc';
import tseslint from 'typescript-eslint';
import reactPlugin from 'eslint-plugin-react';
import reactRecommended from 'eslint-plugin-react/configs/recommended.js';
import reactJSXRuntime from 'eslint-plugin-react/configs/jsx-runtime.js';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
import importPlugin from 'eslint-plugin-import';
const compat = new FlatCompat();
export default tseslint.config(
{
ignores: ['node_modules', '.cache', 'build', 'public/build', '.env'],
},
{
...eslint.configs.recommended,
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
...globals.commonjs,
...globals.es6,
},
parserOptions: {
ecmaFeatures: {
jsx: true
},
},
},
},
{
files: ["**/*.{js,jsx,ts,tsx}"],
...reactRecommended,
...reactJSXRuntime,
rules: {
...reactRecommended.rules,
...reactJSXRuntime.rules,
},
languageOptions: {
...reactRecommended.languageOptions,
...reactJSXRuntime.languageOptions,
},
plugins: {
react: reactPlugin,
['jsx-a11y']: jsxA11yPlugin,
},
extends: [
...compat.config(reactHooksPlugin.configs.recommended),
...compat.config(jsxA11yPlugin.configs.recommended),
],
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
"import/resolver": {
typescript: {},
},
},
},
{
files: ["**/*.{ts,tsx}"],
plugins: {
import: importPlugin,
},
extends: [
...tseslint.configs.recommended,
...compat.config(importPlugin.configs.recommended),
...compat.config(importPlugin.configs.typescript),
],
settings: {
"import/internal-regex": "^~/",
"import/resolver": {
node: {
extensions: [".ts", ".tsx"],
},
typescript: {
alwaysTryTypes: true,
},
},
},
},
);
Node
最後にNode
です。設定ファイルに対するenv
を記述しています。
{
files: [".eslintrc.cjs"],
env: {
node: true,
},
},
eslint
の設定ファイル名だけ変えて、env
をlanguageOptions.globals
にglobals
パッケージを使って記述します。
{
files: ['eslint.config.js'],
languageOptions: {
globals: {
...globals.node
},
},
}
最終的なファイル
最終的なeslint.config.js
は以下のようになりました。
import globals from 'globals';
import eslint from '@eslint/js';
import { FlatCompat } from '@eslint/eslintrc';
import tseslint from 'typescript-eslint';
import reactPlugin from 'eslint-plugin-react';
import reactRecommended from 'eslint-plugin-react/configs/recommended.js';
import reactJSXRuntime from 'eslint-plugin-react/configs/jsx-runtime.js';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
import importPlugin from 'eslint-plugin-import';
const compat = new FlatCompat();
export default tseslint.config(
{
ignores: ['node_modules', '.cache', 'build', 'public/build', '.env'],
},
{
...eslint.configs.recommended,
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
...globals.commonjs,
...globals.es6,
},
parserOptions: {
ecmaFeatures: {
jsx: true
},
},
},
},
{
files: ["**/*.{js,jsx,ts,tsx}"],
...reactRecommended,
...reactJSXRuntime,
rules: {
...reactRecommended.rules,
...reactJSXRuntime.rules,
},
languageOptions: {
...reactRecommended.languageOptions,
...reactJSXRuntime.languageOptions,
},
plugins: {
react: reactPlugin,
['jsx-a11y']: jsxA11yPlugin,
},
extends: [
...compat.config(reactHooksPlugin.configs.recommended),
...compat.config(jsxA11yPlugin.configs.recommended),
],
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
"import/resolver": {
typescript: {},
},
},
},
{
files: ["**/*.{ts,tsx}"],
plugins: {
import: importPlugin,
},
extends: [
...tseslint.configs.recommended,
...compat.config(importPlugin.configs.recommended),
...compat.config(importPlugin.configs.typescript),
],
settings: {
"import/internal-regex": "^~/",
"import/resolver": {
node: {
extensions: [".ts", ".tsx"],
},
typescript: {
alwaysTryTypes: true,
},
},
},
},
{
files: ['eslint.config.js'],
languageOptions: {
globals: {
...globals.node
},
},
}
);
npm run lint
で実行できることを確認してください。エラー用のファイルで想定していたエラーとeslint.config.js
でeslint-plugin-import
のエラーが表示されているはずです。
確認できたら、tseslint
のインポート部分を以下のようにして再度表示されないことを確認したら移行完了です。
import { config, configs } from 'typescript-eslint';
おまけ
VSCodeを使っている方
VSCodeのESLintではFlat Configはまだ実験的に導入されているだけなので、利用している場合はuseFlatConfig
をtrue
にすることを忘れないようにしてください。
{
"eslint.experimental.useFlatConfig": true,
}
ルールをカスタマイズ
remix
の初期設定は推奨されたまま使われていることが多かったので、明示的にルールを追加する方法を紹介します。
typescript-eslint
のno-unused-vars
で_
だけ許可することを考えます。
その場合はplugins
で@typescript-eslint
をtypescript-eslint
のplguin
と対応させてrules
でそのスコープからルールを持ってきて内容を定義すると有効になります。
import { config, configs, plugin } from 'typescript-eslint';
...
...
{
files: ["**/*.{ts,tsx}"],
plugins: {
['@typescript-eslint']: plugin,
},
rules: {
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_"
},
],
},
},
@typescript-eslint
ではない名前をスコープに定義できますが、@typescript-eslint
で宣言することが公式で推奨されています。