I am trying to get prettier, typescript, eslint with airbnb typescript syntax working with linting and auto formatting.
The minimal node package.json
file.
{
"name": "typescript-eslint-airbnb-compat",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "eslint .",
"lint:fix": "npm run lint -- --fix",
"format": "prettier . --check",
"format:fix": "npm run format -- --write"
},
"devDependencies": {
"@eslint/eslintrc": "^3.0.2",
"@eslint/js": "^8.57.0",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"eslint": "^8.57.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^18.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"typescript": "^5.4.3",
"typescript-eslint": "^7.4.0",
"vite": "^5.2.0"
}
}
Here is the flat config file for eslint eslint.config.mjs
.
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import eslintConfigPrettier from "eslint-config-prettier";
import { FlatCompat } from "@eslint/eslintrc";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname
});
export default tseslint.config(
eslint.configs.recommended,
...compat.extends("airbnb-base"),
...compat.extends("airbnb-typescript/base"),
...tseslint.configs.recommendedTypeChecked,
eslintConfigPrettier,
{
languageOptions: {
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
files: ['**/*.{js,jsx,cjs,mjs}'],
extends: [tseslint.configs.disableTypeChecked],
}
);
Airbnb and eslint airbnb ts config do not support the new flat config at the time of writing. Therefore, I am using the compat feature to transform the legacy config into the new syntax.
This is the error I am receiving and I haven't been able to solve it.
> [email protected] lint
> eslint .
Oops! Something went wrong! :(
ESLint: 8.57.0
Error: Key "plugins": Cannot redefine plugin "@typescript-eslint".
at .../typescript-eslint-airbnb-compat/node_modules/@humanwhocodes/object-schema/src/object-schema.js:250:27
at Array.reduce (<anonymous>)
at ObjectSchema.merge (.../typescript-eslint-airbnb-compat/node_modules/@humanwhocodes/object-schema/src/object-schema.js:237:24)
at .../typescript-eslint-airbnb-compat/node_modules/@humanwhocodes/config-array/api.js:935:42
at Array.reduce (<anonymous>)
at FlatConfigArray.getConfig (.../typescript-eslint-airbnb-compat/node_modules/@humanwhocodes/config-array/api.js:934:39)
at FlatConfigArray.isFileIgnored (.../typescript-eslint-airbnb-compat/node_modules/@humanwhocodes/config-array/api.js:962:15)
at .../typescript-eslint-airbnb-compat/node_modules/eslint/lib/eslint/eslint-helpers.js:312:49
at Array.reduce (<anonymous>)
at entryFilter (.../typescript-eslint-airbnb-compat/node_modules/eslint/lib/eslint/eslint-helpers.js:299:28)
Is this a bug or am I taking the wrong step somewhere? I am open to any solution and trying different tools and configs if required.
This has been fixed in typescript-eslint
v7.5.0
If you're stuck on an older version you can manually fix the issue by updating the code:
...compat.extends("airbnb-typescript/base").map(c => {
if (c.plugins) {
// @ts-expect-error
c.plugins['@typescript-eslint'] = tseslint.plugin;
}
return c
}),
Background:
The error is unculear but this is working as expected. TL;DR is that our config defines
{
plugins: {
'@typescript-eslint': require('typescript-eslint').plugin
},
}
But eslint-config-airbnb-typescript
defines
{
plugins: {
'@typescript-eslint': require('@typescript-eslint/eslint-plugin')
},
}
ESLint enforces that whilst you may have multiple definitions of a plugin namespace - each definition must have exactly the same value.
The issue here is that
require('typescript-eslint').plugin !== require('@typescript-eslint/eslint-plugin')
tseslint.configs.recommendedTypeChecked
uses the former and compat.extends("airbnb-typescript/base")
uses the latter.
Hence the error.