ESLintのFlat Config移行でやって良かったこと
ESLintのv9.0.0ではFlat Config(eslint.config.js)がデフォルトになりました。これまでの.eslintrcの形式のファイルも使えますが、ESLINT_USE_FLAT_CONFIG
環境変数を設定する必要があるようです。
これを機にFlat Configで普段使っているルールを整理して書いてみることにしました。その際やって良かったことをまとめます。
作成した設定はSharable Configとして公開しています。
typescript-eslintのtseslint.configを使う
Flat configはこのように配列で書きます。
export default [
{
rules: {
"no-unused-vars": "error",
"no-undef": "error"
}
}
];
これでも良いのですが型があると便利です。typescript-eslintではtseslint.config
というこの配列部分に相当する型を提供してくれる関数を使用できます。
// @ts-check
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
// ここにルールを追加していきます
}
}
);
tseslint.configはextendsが使える
tseslint.config
は引数に対して型を提供しそのまま配列にして返すだけの関数ですが、さらにextends
というプロパティが使用できます。
このextends
は以下のように使用します。
export default tseslint.config({
files: ['**/*.ts'],
extends: [
eslint.configs.recommended,
...tseslint.configs.recommended,
],
rules: {
'@typescript-eslint/array-type': 'error',
'@typescript-eslint/consistent-type-imports': 'error',
},
});
これは以下と同等になります。
export default [
{
files: ['**/*.ts'],
rules: {
// eslint.configs.recommendedが持っているたくさんのルール
}
}
{
files: ['**/*.ts'],
rules: {
// tseslint.configs.recommendedが持っているたくさんのルール
}
}
// その他のtseslint.configs.recommendedのルール(省略)
{
files: ['**/*.ts'],
rules: {
// 最後にもともと指定していたルール
'@typescript-eslint/array-type': 'error',
'@typescript-eslint/consistent-type-imports': 'error',
},
},
];
この関数ではfiles
(またはignores
)で指定した値を、extends
の各ルールとextends
以外それぞれに適用して返すというものです。extends
を持っているオブジェクトは、最終的にexntends
の要素数+1個のオブジェクトになります。
実装を確認してみるとより分かりやすいです。このような短い関数になっています。
これによってeslintやtypescript-eslintの複数の設定にまとめてfiles
を指定することが出来ます。前述の例のように、特定の拡張子のファイルにだけ適用したいルールがある時に便利です。
@eslint/eslintrcと組み合わせる
@eslint/eslintrcのFlatCompat
と組み合わせると、以下のように書くこともできます。
[
{
extends: compat.extends("Flat Configに対応していないライブラリ")
rules: {
// ↑のライブラリのルール
},
}
]
これは↓と結局同じ結果になりますが、1つのプラグインとルールが1つのオブジェクトにまとまっていて見やすいです(感想)。
[
...compat.extends("Flat Configに対応していないライブラリ")
{
rules: {
// ↑のライブラリのルール
},
}
]
作成したルールのスナップショットテストを書く
Flat Config移行前後でルールの変化を見たり、ルールを維持したまま設定の書き方を変えたい場合、スナップショットテストが便利です。
スナップショットテストにはESLint
またはFlatESLint
クラスのcalculateConfigForFile
メソッドが使用できます。
以下のように書くことで.jsファイルへの設定をテストできます。
import { ESLint } from "eslint";
test("index.js", async () => {
const eslint = new ESLint();
const result = await eslint.calculateConfigForFile("index.js");
expect(result).toMatchSnapshot();
});
ESLintがv8の場合
上記のテストはeslintの9.0.0で動作を確認しています。
ESLintのv8では.eslintrcの形式にはESLint
クラスが、Flat ConfigにはFlatESLint
クラスが対応しています。
FlatESLint
クラスはeslint/use-at-your-own-risk
に入っています。自分が試した際は型定義がありませんでしたが、importして使用できました。
import { FlatESLint as ESLint } from "eslint/use-at-your-own-risk.js";
これを利用してESLintクラスで以前の設定を出力し、FlatESLintクラスで新しい設定を出力して比較するということもできるはずです。
ESLintプラグインはFlatCompat無しでも動く(こともある)
eslintのライブラリのうちextendsして使うeslint-config-xxx系のライブラリはFlat Configに対応していなければFlatCompat
のextends
メソッドを使用する必要があります。
eslint-plugin-xxx系のライブラリもFlatCompat
のplugins
メソッドが使えますが、そのままでも意外と動く場合があります。
例えばeslint-plugin-unused-importsでは以下のように書くと動きました。
import unusedImports from "eslint-plugin-unused-imports";
// 省略
{
plugins: {
"unused-imports": unusedImports,
},
rules: {
"@typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "error",
},
},
リポジトリのissueとしても同じ内容のものがありました。
@eslint/config-inspectorが便利
これについても書こうと思っていたのですが、書き始めた当日ちょうど公式から記事が出たのでそのまま載せておきます。
設定したルールが最終的にどのようになったかをUIで確認できるツールです。
おわり
ESLintの設定をFlat Configで書いてみてやったことをまとめました。自分用のSharable Configを作るのおすすめです。
Discussion