eslint-config-complete
Introduction
This is a sharable configuration for ESLint that is intended to be used in TypeScript projects that want to be as safe as possible.
The config is environment-agnostic, meaning that it will work in client-side projects (e.g. React), server-side projects (e.g. Node.js), and so on.
Install
Using complete-lint
This package is part of the complete-lint
meta-linting package. It is recommended that instead of consuming eslint-config-complete
directly, you instead list complete-lint
as a dependency, as that will install both this config and other goodies. (However, complete-lint
will not work with the pnpm package manager, since pnpm does not handle transitive dependencies properly.)
For installation instructions, see the complete-lint
page.
Manually
If you do not want to use the complete-lint
meta-package, then you can install this config manually:
npm install --save-dev eslint typescript eslint-plugin-complete
(eslint
and typescript
are peer-dependencies.)
Usage
Here's an example "eslint.config.mjs" file that loads the base config:
// @ts-check
import { completeConfigBase } from "eslint-config-complete";
import tseslint from "typescript-eslint";
export default tseslint.config(...completeConfigBase);
If you have a monorepo, you might also want to load the monorepo config:
// @ts-check
import {
completeConfigBase,
completeConfigMonorepo,
} from "eslint-config-complete";
import tseslint from "typescript-eslint";
export default tseslint.config(
...completeConfigBase,
...completeConfigMonorepo,
);
Why Do I Need To Use ESLint?
If you are reading this page, you are likely a user of TypeScript. As you probably know, TypeScript is great because it saves you an enormous amount of time. The hours spent troubleshooting run-time errors caused from small typos have become a thing of the past. Good riddance!
But there are many other code problems that do not have to do with types. In the same way that you want to use TypeScript to catch as many bugs as possible, you also want to use ESLint with a config that enables lots of good linting rules to catch even more bugs.
ESLint rules can help catch bugs, but they can also help to make your codebase more consistent and adhere to best-practices within the TypeScript ecosystem. Remember that code is read more often than it is written. If you care about your code being the best that it can possibly be, then using ESLint is a must!
Why Do I Need eslint-config-complete
?
eslint-config-complete
is one of the most comprehensive ESLint configs out there.
Building an ESLint config from scratch takes many, many hours. ESLint has over 250 rules. typescript-eslint
has over 125 rules. And that's just the beginning.
Don't bother creating and maintaining a huge ESLint config yourself. We've done the work to:
- Enable every ESLint rule that we can find from trusted sources that provides value.
- Weed out the rules that don't apply to TypeScript codebases (because many ESLint rules were written before TypeScript existed).
- Weed out the rules covered by Prettier (because many ESLint rules were written before Prettier existed).
- Weed out the rules that are too noisy to provide value (and document them below).
Our Config Philosophy
We want to enable as many lint rules as possible, so that we can catch as many bugs as possible. Of course, this is a tradeoff: with more lint rules, we get more false positives. But in general, a few false positives are worth the time saved from investigating and squashing bugs. (More on false positives later.)
In line with this philosophy, our linting config enables nearly all of the recommended rules from both the core ESLint team and the TypeScript ESLint team, as well as some additional rules that catch even more bugs.
This config also assumes that you are using Prettier to format your TypeScript code, which is considered to be best-practice in the ecosystem. Subsequently, all formatting-related rules that conflict with Prettier are disabled. (However, we use a few formatting-related rules that are not handled by Prettier.)
Auto-Fixing
Deploying this ESLint config on an existing codebase can generate a ton of warnings. Fixing them all might seem overwhelming. While some warnings need to be fixed manually, a ton of ESLint rules have "auto-fixers". This means that the code will fix itself if you run ESLint with the --fix
flag. So, by running npx eslint --fix .
in the root of your project, you can take care of a lot of the warnings automatically.
Additionally, we recommend that you configure your IDE (i.e. VSCode) to automatically run --fix
whenever you save a file.
Dealing with False Positives
Your first reaction to having a bunch of yellow squiggly lines might be to disable any rule that gets in your way. However, even if you think an ESLint warning is superfluous, it is often a sign that your codebase is structured in a bug-prone or non-idiomatic way. Before simply disabling a rule, sometimes it is good to do some research and think carefully if your code can be refactored in some way to be cleaner.
Additionally, some ESLint rules are not about catching bugs, but are about code style and code consistency. If you find the new style to be foreign and weird, it can be tempting to ignore or disable the rule. But before you do that, consider the cost: your codebase will be deviating from others in the TypeScript ecosystem. It is really nice for everyone's code to adhere to the same look and the same standards!
With that said, with so many ESLint rules turned on, you will undoubtedly come across some false positives. You can quickly take care of these by adding a // eslint-disable-next-line insert-rule-name-here
comment. And you can automatically add the comment by selecting "Quick Fix" in VSCode, which is mapped to Ctrl + .
by default.
If you find yourself adding a lot of disable comments for a specific rule, then turn the rule off for the entire project by adding an entry for it in your eslint.config.mjs
file. Some rules won't make sense for every project and that's okay!
Rule List
Below, we provide documentation for every rule that is disabled. (We take a blacklist approach rather than a whitelist approach.)
Core ESLint Rules
@typescript-eslint
Rules
eslint-plugin-import-x
Rules
eslint-plugin-jsdoc
Rules
Rule Name | Enabled | Parent Configs | Notes | Source File |
---|---|---|---|---|
jsdoc/check-access | ❌ | Disabled because it is not needed in TypeScript. | base-jsdoc.js | |
jsdoc/check-alignment | ❌ | Superseded by the complete/limit-jsdoc-comments rule. | base-jsdoc.js | |
jsdoc/check-examples | ❌ | Disabled since it does not work with ESLint 8. | base-jsdoc.js | |
jsdoc/check-indentation | ❌ | Superseded by the complete/limit-jsdoc-comments rule. | base-jsdoc.js | |
jsdoc/check-line-alignment | ❌ | Disabled since this is not a common formatting scheme. It is also not recommended by the plugin authors. | base-jsdoc.js | |
jsdoc/check-param-names | ✅ | base-jsdoc.js | ||
jsdoc/check-property-names | ❌ | Disabled because it is not needed in TypeScript. | base-jsdoc.js | |
jsdoc/check-syntax | ❌ | Disabled because it is not needed in TypeScript. | base-jsdoc.js | |
jsdoc/check-tag-names | ✅ | base-jsdoc.js | ||
jsdoc/check-template-names | ✅ | base-jsdoc.js | ||
jsdoc/check-types | ❌ | Disabled because it is not needed in TypeScript. | base-jsdoc.js | |
jsdoc/check-values | ✅ | base-jsdoc.js | ||
jsdoc/convert-to-jsdoc-comments | ❌ | Disabled since it is idiomatic in the TypeScript ecosystem to use a mixture of both JSDoc and non-JSDoc comments. | base-jsdoc.js | |
jsdoc/empty-tags | ✅ | base-jsdoc.js | ||
jsdoc/implements-on-classes | ✅ | base-jsdoc.js | ||
jsdoc/imports-as-dependencies | ❌ | Disabled since you cannot configure it with a path to the correct "package.json" file. | base-jsdoc.js | |
jsdoc/informative-docs | ✅ | base-jsdoc.js | ||
jsdoc/lines-before-block | ❌ | Disabled since it is currently bugged. | base-jsdoc.js | |
jsdoc/match-description | ❌ | Superseded by the complete/jsdoc-full-sentences rule. | base-jsdoc.js | |
jsdoc/match-name | ❌ | Disabled because it is only needed for projects with specific JSDoc requirements. | base-jsdoc.js | |
jsdoc/multiline-blocks | ❌ | Superseded by the complete/limit-jsdoc-comments rule. | base-jsdoc.js | |
jsdoc/no-bad-blocks | ❌ | Disabled because it provides little value; it only detects JSDoc comments with tags in them. | base-jsdoc.js | |
jsdoc/no-blank-block-descriptions | ❌ | Superseded by the complete/format-jsdoc-comments rule. | base-jsdoc.js | |
jsdoc/no-blank-blocks | ❌ | Superseded by the complete/no-empty-jsdoc rule. | base-jsdoc.js | |
jsdoc/no-defaults | ❌ | Disabled because it provides little value; the @default tag is rare. | base-jsdoc.js | |
jsdoc/no-missing-syntax | ❌ | Disabled because it is too project-specific. | base-jsdoc.js | |
jsdoc/no-multi-asterisks | ❌ | Superseded by the complete/limit-jsdoc-comments rule. | base-jsdoc.js | |
jsdoc/no-restricted-syntax | ❌ | Disabled because it is intended for disabling of specific language features per-project. | base-jsdoc.js | |
jsdoc/no-types | ✅ | The contexts option is set to any to make the rule stricter. | base-jsdoc.js | |
jsdoc/no-undefined-types | ❌ | Disabled because it is not needed in TypeScript. | base-jsdoc.js | |
jsdoc/require-asterisk-prefix | ✅ | base-jsdoc.js | ||
jsdoc/require-description | ❌ | Disabled because it is overboard for every function to have a description. | base-jsdoc.js | |
jsdoc/require-description-complete-sentence | ❌ | Superseded by the complete/jsdoc-complete-sentences rule. | base-jsdoc.js | |
jsdoc/require-example | ❌ | Disabled because it is overboard for every function to require an example. | base-jsdoc.js | |
jsdoc/require-file-overview | ❌ | Disabled because it is overboard for every file to require an overview. | base-jsdoc.js | |
jsdoc/require-hyphen-before-param-description | ✅ | The never option is provided to make the rule match the format of the official TypeScript codebase. | base-jsdoc.js | |
jsdoc/require-jsdoc | ❌ | Disabled since it is overboard for every function to have a JSDoc comment. | base-jsdoc.js | |
jsdoc/require-param | ✅ | Configured to only apply when there are one or more parameters. | base-jsdoc.js | |
jsdoc/require-param-description | ✅ | The contexts option is set to any to make the rule stricter. | base-jsdoc.js | |
jsdoc/require-param-name | ✅ | The contexts option is set to any to make the rule stricter. | base-jsdoc.js | |
jsdoc/require-param-type | ❌ | Disabled because it is not needed in TypeScript. | base-jsdoc.js | |
jsdoc/require-property | ❌ | Disabled because it is not needed in TypeScript. | base-jsdoc.js | |
jsdoc/require-property-description | ✅ | base-jsdoc.js | ||
jsdoc/require-property-name | ✅ | base-jsdoc.js | ||
jsdoc/require-property-type | ❌ | Disabled because it is not needed in TypeScript. | base-jsdoc.js | |
jsdoc/require-returns | ❌ | Disabled because it is overboard for every function to document every return value. | base-jsdoc.js | |
jsdoc/require-returns-check | ❌ | Disabled because it is overboard for every function to document every return value. | base-jsdoc.js | |
jsdoc/require-returns-description | ✅ | The contexts option is set to any to make the rule stricter. | base-jsdoc.js | |
jsdoc/require-returns-type | ❌ | Disabled because it is not needed in TypeScript. | base-jsdoc.js | |
jsdoc/require-template | ❌ | Disabled because it is overboard to document every generic type variable. | base-jsdoc.js | |
jsdoc/require-throws | ❌ | Disabled because it is overboard to document every throw statement. | base-jsdoc.js | |
jsdoc/require-yields | ❌ | Disabled because it is overboard to document every yield. | base-jsdoc.js | |
jsdoc/require-yields-check | ❌ | Disabled because it is overboard to document every yield. | base-jsdoc.js | |
jsdoc/sort-tags | ❌ | Disabled because it is not very useful. In most cases, a function will only have @param and @return tags, making sorting unnecessary. | base-jsdoc.js | |
jsdoc/tag-lines | ❌ | Superseded by the complete/format-jsdoc-comments rule. | base-jsdoc.js | |
jsdoc/text-escaping | ❌ | Disabled since it is only useful in certain environments (e.g. when your project converts JSDoc comments to Markdown). | base-jsdoc.js | |
jsdoc/valid-types | ❌ | Disabled because it is not needed in TypeScript. | base-jsdoc.js |
eslint-plugin-n
Rules
Rule Name | Enabled | Parent Configs | Notes | Source File |
---|---|---|---|---|
n/callback-return | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/exports-style | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/file-extension-in-import | ✅ | This rule is helpful to automatically fix file extensions in import statements throughout an entire codebase. | base-n.js | |
n/global-require | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/handle-callback-err | ✅ | base-n.js | ||
n/hashbang | ❌ | Disabled since it does not work very well with TypeScript. (It needs project-specific configuration depending on where the output directory is located.) | base-n.js | |
n/no-callback-literal | ✅ | base-n.js | ||
n/no-deprecated-api | ✅ | base-n.js | ||
n/no-exports-assign | ✅ | base-n.js | ||
n/no-extraneous-import | ❌ | Disabled since it is handled by the TypeScript compiler. | base-n.js | |
n/no-extraneous-require | ❌ | Disabled since require statements are not used in TypeScript code. | base-n.js | |
n/no-hide-core-modules | ❌ | Disabled because this rule is deprecated. | base-n.js | |
n/no-missing-import | ❌ | Disabled since it is handled by the TypeScript compiler. | base-n.js | |
n/no-missing-require | ❌ | Disabled since it is handled by the TypeScript compiler. | base-n.js | |
n/no-mixed-requires | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/no-new-require | ✅ | base-n.js | ||
n/no-path-concat | ✅ | base-n.js | ||
n/no-process-env | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/no-process-exit | ❌ | Disabled because using process.exit is common to exit command-line applications without verbose output. | base-n.js | |
n/no-restricted-import | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/no-restricted-require | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/no-sync | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/no-unpublished-bin | ✅ | base-n.js | ||
n/no-unpublished-import | ✅ | An exception is made for files in a "scripts" directory, since those should be allowed to import from "devDependencies". | base-n.js | |
n/no-unpublished-require | ✅ | base-n.js | ||
n/no-unsupported-features/es-builtins | ❌ | Disabled because it is assumed that we are running on modern versions of Node.js. | base-n.js | |
n/no-unsupported-features/es-syntax | ❌ | Disabled because it is assumed that our transpiler or runtime has support for the latest version of ESM. | base-n.js | |
n/no-unsupported-features/node-builtins | ❌ | Disabled since it is handled by the TypeScript compiler. | base-n.js | |
n/prefer-global/buffer | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/prefer-global/console | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/prefer-global/process | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/prefer-global/text-decoder | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/prefer-global/text-encoder | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/prefer-global/url | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/prefer-global/url-search-params | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/prefer-node-protocol | ❌ | Superseded by the unicorn/prefer-node-protocol rule. | base-n.js | |
n/prefer-promises/dns | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/prefer-promises/fs | ❌ | Disabled since stylistic rules from this plugin are not used. | base-n.js | |
n/process-exit-as-throw | ✅ | base-n.js | ||
n/shebang | ❌ | Superseded by the n/hashbang rule. | base-n.js |
eslint-plugin-unicorn
Rules
eslint-plugin-complete
Rules
Rule Name | Enabled | Parent Configs | Notes | Source File |
---|---|---|---|---|
complete/complete-sentences-jsdoc |