My (@connorjs) preferred ESLint configuration. With ESLint flat config.
Use it directly (§ Install) or take inspiration from it (§ Rules and reasoning).
🛑 IMPORTANT
eslint-comments/require-description is the single most important rule to configure! Please use it.
🟢 Tip: I highly recommend eslint-plugin-unicorn, which my config uses.
-
Add the dependency
npm i -D eslint-config-connorjs
-
Include the config in your ESLint flat config.
import connorjsConfig from "eslint-config-connorjs"; export default [ // earlier configuration ...connorjsConfig, // later ];
To learn more about ESLint flat config, check out the blog posts or the documentation.
The lib directory contains the ESLint configuration files.
It groups them by “use case.”
A use case could represent an entire language (html
or json
for example) or a tool (react
or vitest
).
Splitting by use case helps to copy desired configuration or building a functional form of the ESLint config. (See Sheriff for an example of the functional form.)
The remainder of the README discusses the rules, configurations, and plugins used and why I used them.
The 🔧 emoji indicates that configured rules are automatically fixable with --fix
.
🟢 Tip: The source code has inline comments that may provide more detail.
The base rules config apply to all file types.
-
Configures ESLint linter options.
- reportUnusedDisableDirectives to keep code clean and up to date.
-
Includes eslint-plugin-eslint-comments and enforces comment descriptions (eslint-comments/require-description) to document why the code should ignore a configured ESLint rule.
-
Includes eslint-config-prettier to turns off all rules that are unnecessary or might conflict with Prettier.
-
🔧 Enforces template literals (backtick strings) to allow easier change to interpolation with eslint/quotes.
-
Configures the global ignores.
The JSON config applies to all JSON files. It handles JSONC (JSON with comments) and JSONC-like files.
-
Configures jsonc-eslint-parser as the parser for the
.json
and.jsonc
files.It does not lint
package-lock.json
. -
Includes eslint-plugin-jsonc and registers its
recommended-with-json
andprettier
rule sets. -
🔧 Configures sorting rules to standardize the order (no need to think or worry about the “best” order) and reduces merge conflicts. Feel free to
eslint-disable
at call sites. -
Allows comments in JSONC and JSONC-like files (for example,
tsconfig.json
). -
🔧 Configures an explicit sort order for
package.json
keys. See the code for details.🔷 Note: This overrides the previous jsonc/sort-keys configuration. You can configure specific sort orders for other files using similar logic.
The JS and TS config applies to all JS and
TS files: cjs,js,ts,tsx
. The largest configuration set!
-
Configures language options.
-
ecmaVersion: latest
because projects use bundlers or other build tools to transpile to target versions. -
Includes isomorphic globals (shared by node and the browser) via globals
-
Also see the @typescript-eslint/parser documentation
-
-
🔧 Configures sorting rules to standardize the order (no need to think or worry about the “best” order) and reduces merge conflicts. Feel free to
eslint-disable
at call sites. They are case-insensitive.-
🔧 @typescript-eslint/member-ordering with required properties first
-
Includes @eslint/js
recommended
rule set. -
Includes eslint-plugin-sonarjs
recommended
rule set. -
Includes eslint-plugin-unicorn
recommended
rule set and configures additional rules from unicorn. Some specific call-outs follow.-
🔧 Configures an allow list for unicorn/prevent-abbreviations to allow some abbreviations. Example: Allow
props
, which React commonly uses. -
🔧 Configures patterns for unicorn/string-content to enforce better string content. Example: Use unicode arrow
→
instead of hyphen and greater than (->
).The auto-fix feature makes this rule very useful. See the source code for a “smart quotes” pattern.
-
-
Uses typescript-eslint and includes its
recommended-type-checked
andstylistic-type-checked
rule sets.-
🔧 Configures @typescript-eslint/consistent-type-definitions to enforce using
type
instead ofinterface
(as the default).Interfaces use declaration merging, which I do not recommend as the default. See the Differences Between Type Aliases and Interfaces documentation.
-
🔧 Configures @typescript-eslint/no-non-null-assertion to require a comment via
eslint-disable
when needed. It allows non-null assertions in test files.
-
-
Uses eslint-plugin-simple-import-sort and eslint-plugin-import to configure import rules. Some specific call-outs follow.
-
🔧 Includes
simple-import-sort/imports
andsimple-import-sort/exports
to sort the imports and re-exports. See the Sort order docs.I recommend the default configuration instead of creating your own order.
-
Includes eslint-plugin-import
recommended
rule set. -
Configures import/no-default-export to disallow default exports.
I have experienced various issues resulting from default exports over the years, so I strongly recommend configuring this rule. You can always
eslint-disable
at the call site when you need it and explain why (example: dynamic imports for React code-splitting point).- Naming exports leads to a stronger contract and can help refactoring.
- You can use
as
syntax to rename named exports very easily, so the supposed benefit of “name default exports whatever you want” has little benefit in practice. - I want to add more of my reasons, so TODO!
The ESLint configuration opts-out known configuration files that require default exports (example: storybook files).
-
Configures import/no-anonymous-default-export to disallow anonymous default exports in the case that you
eslint-disable
theimport/no-default-export
rule. -
🔧 Uses @typescript-eslint/consistent-type-imports and import/consistent-type-specifier-style to enforce consistent usage of type imports.
We need both rules for best fix-it developer experience: one to add
type
and the other to fix the placement.
-
The react config applies to all typescript files (ts
and tsx
) and only makes sense to use in a React project.
-
Uses eslint-plugin-jsx-a11y and its
recommended
rule set. -
Uses eslint-plugin-react and its
recommended
andjsx-runtime
rule sets. -
Uses eslint-plugin-react-hooks and its
recommended
rule set. -
Configures react/destructuring-assignment to disallow destructuring props. (Controversial, I know.)
I find it harder to update components that use destructuring. Plus I think it looks bad with inline types given TypeScript usage.
-
Configures react/forbid-component-props to disallow props. (Example:
style
to disallow inline styles.) -
🔧 Configures [react/function-component-definition] to enforce component definition consistency.
Uses “function declarations” for named components because they are the only way to support generics in TSX, so using it for consistency. Remember: This will auto-fix.
Uses “arrow functions” for unnamed components to emphasize unnamed and for nice lambda readability (example: pass to
map
). -
🔧 Enables react/hook-use-state to enforce symmetric naming of the
useState
hook value and setter variables. -
🔧 Configures react/jsx-boolean-value and react/jsx-curly-brace-presence to enforce consistent JSX styles. See the code for details.
-
Configures the following rules to force a comment explaining the use case. While this may seem like extra work, it helps catch improper usage.
- react/jsx-no-leaked-render
- react/jsx-props-no-spreading
- react/no-array-index-key
- react/no-danger
The HTML config applies to all HTML files.
-
Uses html-eslint.
-
Includes the
recommended
ruleset and accessibility and best practice oriented rules. See the code for details, but some specific call-outs follow.-
@html-eslint/id-naming-convention to enforce kebab case for
id
naming. -
@html-eslint/no-inline-styles to disallow inline styles, mostly for Content Security Policy (CSP) reasons.
Even if you allow
unsafe-inline
for the CSP, this rule would also require explanations for using inline styles instead of CSS witheslint-disable
. -
@html-eslint/no-skip-heading-levels to disallow skipping heading levels.
-
@html-eslint/no-target-blank to disallow usage of unsafe
target='_blank'
.
-