Description
Before You File a Documentation Request Please Confirm You Have Done The Following...
- I have looked for existing open or closed documentation requests that match my proposal.
- I have read the FAQ and my problem is not listed.
Suggested Changes
Here's my real-life config:
import jsEslint from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier/flat";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import globals from "globals";
import tsEslint from "typescript-eslint";
export default tsEslint.config(
jsEslint.configs.recommended,
tsEslint.configs.recommendedTypeChecked,
tsEslint.configs.stylisticTypeChecked,
reactHooks.configs["recommended-latest"],
reactRefresh.configs.recommended,
reactRefresh.configs.vite,
{
ignores: ["dist"],
},
{
languageOptions: {
parserOptions: {
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
tsconfigRootDir: import.meta.dirname,
},
ecmaVersion: 2020,
globals: globals.browser,
},
},
{
files: ["**/*.js", "**/*.mjs"],
extends: [tsEslint.configs.disableTypeChecked],
},
eslintConfigPrettier,
);
After setting it up, it turned out there's just one rule I'd like to override, so I turned my config into:
export default tsEslint.config(
// ... configs
{
ignores: ["dist"],
},
{
languageOptions: {
parserOptions: {
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
tsconfigRootDir: import.meta.dirname,
},
ecmaVersion: 2020,
globals: globals.browser,
},
rules: {
// The rule I added:
"@typescript-eslint/consistent-type-definitions": "off",
},
},
{
files: ["**/*.js", "**/*.mjs"],
extends: [tsEslint.configs.disableTypeChecked],
},
eslintConfigPrettier,
);
I expected this to simply merge with the existing rules, but it turned out it overwrote all the previously set rules, including react-hooks/rules-of-hooks
and react-refresh/only-export-components
.
My first instinct was to manually re-add all the previously defined rules:
export default tsEslint.config(
// ... configs
{
ignores: ["dist"],
},
{
languageOptions: {
parserOptions: {
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
tsconfigRootDir: import.meta.dirname,
},
ecmaVersion: 2020,
globals: globals.browser,
},
rules: {
// The rules I brought back:
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"react-refresh/only-export-components": "error",
"@typescript-eslint/consistent-type-definitions": "off",
},
},
{
files: ["**/*.js"<
78B8
/span>, "**/*.mjs"],
extends: [tsEslint.configs.disableTypeChecked],
},
eslintConfigPrettier,
);
It worked, but the manual process didn't feel right or elegant, so I started fiddling around and figured out that I have to append the rules
into the next array item, instead of adding it to the entry that contains languageOptions
.
I ended up with:
import jsEslint from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier/flat";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import globals from "globals";
import tsEslint from "typescript-eslint";
export default tsEslint.config(
// ... configs
{
ignores: ["dist"],
},
{
languageOptions: {
parserOptions: {
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
tsconfigRootDir: import.meta.dirname,
},
ecmaVersion: 2020,
globals: globals.browser,
},
},
{
rules: {
"@typescript-eslint/consistent-type-definitions": "off",
},
},
{
files: ["**/*.js", "**/*.mjs"],
extends: [tsEslint.configs.disableTypeChecked],
},
eslintConfigPrettier,
);
It was just a trial-and-error process that led me to that solution, but after figuring it out I still don't really understand why it worked. Why does having rules
together with languageOptions
prevent merging, whereas a separate entry containing just the rules
object is correctly merged?
What I'm proposing is adding a very explicit explanation on how to add custom rule overrides in a safe way - so that preceding rules aren't overridden OR, and maybe it's a better option, clarify how the tsEslint.config()
performs merging: what's being merged and what is not.
Affected URL(s)
https://typescript-eslint.io/packages/typescript-eslint#config
Additional Info
No response