eslint

ESLint Flat Config with TypeScript

ESLint flat config (eslint.config.js) for TypeScript projects with recommended rules, import sorting, and React support.

Overview

ESLint’s flat config format (eslint.config.js) replaces the legacy .eslintrc files. This configuration sets up TypeScript-aware linting with recommended rules, import organization, and optional React support using the new flat config API.

Configuration

// eslint.config.js

import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import importPlugin from "eslint-plugin-import";
import prettierConfig from "eslint-config-prettier";

export default tseslint.config(
  // ── Global Ignores ──
  {
    ignores: [
      "dist/",
      "build/",
      "node_modules/",
      "coverage/",
      "*.config.js",                   // Don't lint config files
      "**/*.d.ts",                     // Skip declaration files
    ],
  },

  // ── Base ESLint Recommended Rules ──
  eslint.configs.recommended,

  // ── TypeScript Recommended Rules ──
  ...tseslint.configs.recommendedTypeChecked,
  ...tseslint.configs.stylisticTypeChecked,

  // ── TypeScript Parser Configuration ──
  {
    languageOptions: {
      parserOptions: {
        projectService: true,          // Auto-detect tsconfig.json
        tsconfigRootDir: import.meta.dirname,
      },
    },
  },

  // ── Import Organization ──
  {
    plugins: {
      import: importPlugin,
    },
    rules: {
      "import/order": [
        "error",
        {
          groups: [
            "builtin",                 // Node.js built-ins (fs, path)
            "external",                // npm packages
            "internal",                // Path aliases (@/*)
            "parent",                  // Parent imports (../)
            "sibling",                 // Same directory (./)
            "index",                   // Index file (./)
          ],
          "newlines-between": "always",
          alphabetize: {
            order: "asc",
            caseInsensitive: true,
          },
        },
      ],
      "import/no-duplicates": "error", // Merge imports from same module
    },
  },

  // ── Custom Rules ──
  {
    rules: {
      // TypeScript-specific
      "@typescript-eslint/no-unused-vars": [
        "error",
        {
          argsIgnorePattern: "^_",     // Allow _unused parameters
          varsIgnorePattern: "^_",     // Allow _unused variables
        },
      ],
      "@typescript-eslint/consistent-type-imports": [
        "error",
        { prefer: "type-imports" },    // Enforce `import type { Foo }`
      ],
      "@typescript-eslint/no-import-type-side-effects": "error",
      "@typescript-eslint/no-floating-promises": "error",    // Must await promises
      "@typescript-eslint/no-misused-promises": "error",     // No promises in void contexts
      "@typescript-eslint/require-await": "error",

      // General quality
      "no-console": ["warn", { allow: ["warn", "error"] }], // Allow console.warn/error
      "prefer-const": "error",         // Use const when variable isn't reassigned
      eqeqeq: ["error", "always"],     // Require === instead of ==
      curly: ["error", "all"],         // Require braces for all blocks
    },
  },

  // ── Prettier Compatibility (must be last) ──
  prettierConfig,
);

Key Options Explained

  • tseslint.config() — Helper that provides proper typing and merging for flat config objects. Accepts spread arrays from preset configs.
  • recommendedTypeChecked — Enables rules that use TypeScript’s type information for deeper analysis (e.g., detecting floating promises, type misuse).
  • projectService: true — Automatically finds and uses the nearest tsconfig.json for each file. Replaces the older project: true option.
  • consistent-type-imports — Enforces import type { Foo } for type-only imports, enabling better tree-shaking and faster builds.
  • argsIgnorePattern: "^_" — Allows unused function parameters prefixed with underscore, common for callbacks like (_req, res).
  • eslint-config-prettier — Disables all ESLint rules that conflict with Prettier formatting. Must be the last config in the array.
  • import/order — Enforces a consistent import ordering with automatic grouping and alphabetical sorting within groups.

Common Modifications

  • Add React: Install eslint-plugin-react and eslint-plugin-react-hooks, then add reactPlugin.configs.flat.recommended and reactHooksPlugin.configs['recommended-latest'] to the config array.
  • Next.js: Use @next/eslint-plugin-next with nextPlugin.configs['core-web-vitals'] for Next.js-specific rules.
  • Disable type-checked rules: Replace recommendedTypeChecked with recommended if type-aware linting is too slow for your project.
  • Allow console.log: Change "no-console" to "off" in development or use environment-based configuration.
  • Custom path aliases: Add settings: { "import/resolver": { typescript: true } } with eslint-import-resolver-typescript for path alias resolution.