ESLintで「未使用importを保存時に自動削除」+「import順を自動整列」する(flat config)

目次
import の整理は地味に手間です。使わなくなった import が残る、並び順がバラバラになる——これを 保存(Ctrl+S)するだけで自動で 片付けたい。結論、必要なのは次の組み合わせです。
- 未使用 import の自動削除 →
eslint-plugin-unused-imports(削除フィクサー付き) - import 順の自動整列 →
eslint-plugin-simple-import-sort - 保存時に発火 → VS Code の
editor.codeActionsOnSaveにsource.fixAll.eslint - 整形は Prettier に一任(ESLint と役割分担)
ハマりどころは「@typescript-eslint/no-unused-vars は未使用 import を検出はするが自動削除できない」点。ここを差し替えるのが肝です。以下、ESLint flat config(v9)前提でまとめます。
なぜ no-unused-vars では消えないのか
TypeScript プロジェクトでよく使う @typescript-eslint/no-unused-vars は、未使用の変数・import をエラーとして報告してくれます。ただしこのルールには fixer(自動修正)が無いので、--fix や保存時アクションでは消えません。赤線は出るのに自分で消すしかない、という状態になりがちです。
そこで eslint-plugin-unused-imports を使います。こちらの no-unused-imports ルールは fixer 付きで、--fix(=保存時の source.fixAll.eslint)で該当 import 行を自動削除します。
インストール
pnpm add -D eslint-plugin-unused-imports eslint-plugin-simple-import-sort(simple-import-sort を既に入れているなら unused-imports だけでOK)
ESLint flat config
eslint.config.mjs にプラグインとルールを追加します。ポイントは @typescript-eslint/no-unused-vars を off にして、unused-imports 側に寄せること(両方有効だと二重報告になる)。
import simpleImportSort from "eslint-plugin-simple-import-sort";
import unusedImports from "eslint-plugin-unused-imports";
export default [
// ...(next / typescript などの既存 config)
{
plugins: {
"simple-import-sort": simpleImportSort,
"unused-imports": unusedImports,
},
rules: {
// import / export の並び順を自動整列(--fix で修正される)
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
// 未使用 import は unused-imports で検出(フィクサー付き→保存時に自動削除)
// 重複報告を避けるため TS 標準ルールは off にする
"@typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "error",
// 未使用「変数」はエラー(_ 始まりは意図的な未使用として許可)
"unused-imports/no-unused-vars": [
"error",
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
],
},
},
];unused-imports/no-unused-vars は、import ではない普通の未使用変数を拾う担当です。argsIgnorePattern / varsIgnorePattern で _ 始まりだけ許可しておくと、意図的な未使用((_req, res) => ... など)を握りつぶせます。
VS Code:保存(Ctrl+S)で自動適用
ここまではルール定義。実際に保存時に走らせるには、.vscode/settings.json で codeActionsOnSave に ESLint の fixAll を指定します。
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
}
}これで保存すると 「未使用 import 削除 → import 並び替え → Prettier 整形」 が一括でかかります。
source.fixAll.eslint… ESLint の自動修正(unused-imports の削除+simple-import-sort の整列)editor.formatOnSave+ Prettier … 整形(インデント・引用符など)- 前提: VS Code に ESLint 拡張(dbaeumer.vscode-eslint) と Prettier 拡張(esbenp.prettier-vscode) が入っていること
"source.fixAll.eslint"の値は"explicit"(保存時に実行)。旧来のtrue/falseは非推奨で、"explicit"/"always"/"never"を使います。
モノレポで効かないとき
ルートに複数プロジェクトがある構成では、ESLint 拡張が flat config を見つけられず何も起きないことがあります。その場合は working directory を自動解決させます。
{
"eslint.workingDirectories": [{ "mode": "auto" }]
}Prettier と喧嘩させない
import の並び替えは simple-import-sort(ESLint)、コードの整形は Prettier、と役割を分けます。両者がバッティングしないよう、ESLint 側の整形系ルールは eslint-config-prettier で無効化しておくのが定石です(flat config なら末尾付近で読み込む)。
import prettier from "eslint-config-prettier/flat";
export default [
// ...他の config
prettier, // 整形系ルールを無効化。他より後ろに置く
];import の並び順は Prettier の管轄外なので、simple-import-sort と競合しません。安心して併用できます。
動作確認
未使用 import と順序バラバラのファイルを用意して --fix すると、こうなります。
pnpm exec eslint --fix path/to/file.tsx// before
import { useState } from "react"; // 未使用
import Image from "next/image";
import { QueryClient } from "@tanstack/react-query"; // 未使用
// after(未使用が消え、必要な import だけ残る)
import Image from "next/image";CI でも同じルールで eslint(--max-warnings=0 推奨)を走らせておけば、ローカルの保存時修正と CI の判定が完全に揃います。
まとめ
- 未使用 import を消したいなら
eslint-plugin-unused-imports。@typescript-eslint/no-unused-varsは fixer が無いので off にして置き換える - import 順は
eslint-plugin-simple-import-sort(--fixで整列) - 保存時発火は VS Code の
editor.codeActionsOnSave: { "source.fixAll.eslint": "explicit" } - 整形は Prettier に一任し、
eslint-config-prettierを末尾で読み込んで競合を消す - CI でも同じ ESLint を回してローカルと揃える
参考ソース
関連記事

TanStack Query を Next.js App Router の静的エクスポート構成に入れる手順を、Providerの初期化(use client)→layoutラップ→共通fetch(lib/api.ts)→hooks(1ファイル1フック)→コンポーネントでの使い方、まで一気通貫でまとめます。

create-next-app から Amplify Gen2 のバックエンド(Cognito/DynamoDB/Lambda)を追加し、Server Actions での SSR 書き込み、Lambda を API Gateway で REST 公開、Next.js API Route、Amplify Hosting の Git 連携デプロイまでを一気通貫でまとめます。

git ルートに husky を置き、frontend の ESLint(no-console・any 禁止・未使用/import 整列)と Prettier(Tailwind クラス整列)を lint-staged 経由で pre-commit 自動実行する構成を、実際の設定ファイルとハマりどころつきで解説します。