diff --git a/docs/linting/Configurations.mdx b/docs/linting/Configurations.mdx
index 3d56abb8af0..9048a1605a9 100644
--- a/docs/linting/Configurations.mdx
+++ b/docs/linting/Configurations.mdx
@@ -15,14 +15,14 @@ title: Configurations
If your project does not enable [typed linting](./Typed_Linting.mdx), we suggest enabling the [`recommended`](#recommended) and [`stylistic`](#stylistic) configurations to start:
-```json
-{
- "extends": [
- "eslint:recommended",
- "plugin:@typescript-eslint/recommended",
- "plugin:@typescript-eslint/stylistic"
- ]
-}
+```js title=".eslintrc.js"
+module.exports = {
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:@typescript-eslint/stylistic',
+ ],
+};
```
> If a majority of developers working on your project are comfortable with TypeScript and typescript-eslint, consider replacing `recommended` with `strict`.
@@ -31,14 +31,14 @@ If your project does not enable [typed linting](./Typed_Linting.mdx), we suggest
If your project enables [typed linting](./Typed_Linting.mdx), we suggest enabling the [`recommended-type-checked`](#recommended-type-checked) and [`stylistic-type-checked`](#stylistic-type-checked) configurations to start:
-```json
-{
- "extends": [
- "eslint:recommended",
- "plugin:@typescript-eslint/recommended-type-checked",
- "plugin:@typescript-eslint/stylistic-type-checked"
- ]
-}
+```js title=".eslintrc.js"
+module.exports = {
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended-type-checked',
+ 'plugin:@typescript-eslint/stylistic-type-checked',
+ ],
+};
```
> If a majority of developers working on your project are comfortable with TypeScript and typescript-eslint, consider replacing `recommended-type-checked` with `strict-type-checked`.
@@ -70,10 +70,10 @@ Recommended rules for code correctness that you can drop in without additional c
These rules are those whose reports are almost always for a bad practice and/or likely bug.
`recommended` also disables core ESLint rules known to conflict with typescript-eslint rules or cause issues in TypeScript codebases.
-```json
-{
- "extends": ["plugin:@typescript-eslint/recommended"]
-}
+```js title=".eslintrc.js"
+module.exports = {
+ extends: ['plugin:@typescript-eslint/recommended'],
+};
```
See [`configs/recommended.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/recommended.ts) for the exact contents of this config.
@@ -83,10 +83,10 @@ See [`configs/recommended.ts`](https://github.com/typescript-eslint/typescript-e
Contains all of `recommended` along with additional recommended rules that require type information.
Rules newly added in this configuration are similarly useful to those in `recommended`.
-```json
-{
- "extends": ["plugin:@typescript-eslint/recommended-type-checked"]
-}
+```js title=".eslintrc.js"
+module.exports = {
+ extends: ['plugin:@typescript-eslint/recommended-type-checked'],
+};
```
See [`configs/recommended-type-checked.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/recommended-type-checked.ts) for the exact contents of this config.
@@ -96,10 +96,10 @@ See [`configs/recommended-type-checked.ts`](https://github.com/typescript-eslint
Contains all of `recommended`, as well as additional strict rules that can also catch bugs.
Rules added in `strict` are more opinionated than recommended rules and might not apply to all projects.
-```json
-{
- "extends": ["plugin:@typescript-eslint/strict"]
-}
+```js title=".eslintrc.js"
+module.exports = {
+ extends: ['plugin:@typescript-eslint/strict'],
+};
```
See [`configs/strict.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/strict.ts) for the exact contents of this config.
@@ -113,10 +113,10 @@ We recommend a TypeScript project extend from `plugin:@typescript-eslint/strict`
Contains all of `recommended`, `recommended-type-checked`, and `strict`, along with additional strict rules that require type information.
Rules newly added in this configuration are similarly useful (and opinionated) to those in `strict`.
-```json
-{
- "extends": ["plugin:@typescript-eslint/strict-type-checked"]
-}
+```js title=".eslintrc.js"
+module.exports = {
+ extends: ['plugin:@typescript-eslint/strict-type-checked'],
+};
```
See [`configs/strict-type-checked.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/strict-type-checked.ts) for the exact contents of this config.
@@ -130,10 +130,10 @@ We recommend a TypeScript project extend from `plugin:@typescript-eslint/strict-
Rules considered to be best practice for modern TypeScript codebases, but that do not impact program logic.
These rules are generally opinionated about enforcing simpler code patterns.
-```json
-{
- "extends": ["plugin:@typescript-eslint/stylistic"]
-}
+```js title=".eslintrc.js"
+module.exports = {
+ extends: ['plugin:@typescript-eslint/stylistic'],
+};
```
See [`configs/stylistic.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/stylistic.ts) for the exact contents of this config.
@@ -143,18 +143,17 @@ See [`configs/stylistic.ts`](https://github.com/typescript-eslint/typescript-esl
Contains all of `stylistic`, along with additional stylistic rules that require type information.
Rules newly added in this configuration are similarly opinionated to those in `stylistic`.
-```json
-{
- "extends": ["plugin:@typescript-eslint/stylistic-type-checked"]
-}
+```js title=".eslintrc.js"
+module.exports = {
+ extends: ['plugin:@typescript-eslint/stylistic-type-checked'],
+};
```
See [`configs/stylistic-type-checked.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/strict-type-checked.ts) for the exact contents of this config.
## Other Configurations
-typescript-eslint includes a scattering of utility configurations used by the recommended configurations.
-We don't recommend using these directly; instead, extend from an earlier recommended rule.
+typescript-eslint includes a few utility configurations.
### `all`
@@ -171,26 +170,51 @@ Many rules conflict with each other and/or are intended to be configured per-pro
### `base`
A minimal ruleset that sets only the required parser and plugin options needed to run typescript-eslint.
-
-
+We don't recommend using this directly; instead, extend from an earlier recommended rule.
This config is automatically included if you use any of the recommended configurations.
See [`configs/base.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/base.ts) for the exact contents of this config.
+### `disable-type-checked`
+
+A utility ruleset that will disable type-aware linting and all type-aware rules available in our project.
+This config is useful if you'd like to have your base config concerned with type-aware linting, and then conditionally use [overrides](https://eslint.org/docs/latest/use/configure/configuration-files#configuration-based-on-glob-patterns) to disable type-aware linting on specific subsets of your codebase.
+
+See [`configs/disable-type-checked.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/disable-type-checked.ts) for the exact contents of this config.
+
+:::info
+If you use type-aware rules from other plugins, you will need to manually disable these rules or use a premade config they provide to disable them.
+:::
+
+```js title=".eslintrc.js"
+module.exports = {
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/eslint-recommended',
+ ],
+ overrides: [
+ {
+ files: ['*.js'],
+ extends: ['plugin:@typescript-eslint/disable-type-checked'],
+ },
+ ],
+};
+```
+
### `eslint-recommended`
This ruleset is meant to be used after extending `eslint:recommended`.
It disables core ESLint rules that are already checked by the TypeScript compiler.
Additionally, it enables rules that promote using the more modern constructs TypeScript allows for.
-```jsonc
-{
- "extends": [
- "eslint:recommended",
- "plugin:@typescript-eslint/eslint-recommended"
- ]
-}
+```js title=".eslintrc.js"
+module.exports = {
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/eslint-recommended',
+ ],
+};
```
This config is automatically included if you use any of the recommended configurations.
diff --git a/docs/linting/Typed_Linting.mdx b/docs/linting/Typed_Linting.mdx
index cadeabcde3c..3be80a97aa8 100644
--- a/docs/linting/Typed_Linting.mdx
+++ b/docs/linting/Typed_Linting.mdx
@@ -55,7 +55,7 @@ module.exports = {
};
```
-See [the `@typescript-eslint/parser` docs for more details](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/README.md#parseroptionsproject).
+See [the `@typescript-eslint/parser` docs for more details](../architecture/Parser.mdx#project).
:::note
If your project is a multi-package monorepo, see [our docs on configuring a monorepo](./typed-linting/Monorepos.mdx).
@@ -63,6 +63,39 @@ If your project is a multi-package monorepo, see [our docs on configuring a mono
## FAQs
+### How can I disable type-aware linting for a subset of files?
+
+You can combine ESLint's [overrides](https://eslint.org/docs/latest/use/configure/configuration-files#configuration-based-on-glob-patterns) config in conjunction with our [`disable-type-checked`](./Configurations.mdx#disable-type-checked) config to turn off type-aware linting on specific subsets of files.
+
+```js title=".eslintrc.js"
+module.exports = {
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:@typescript-eslint/recommended-type-checked',
+ ],
+ plugins: ['@typescript-eslint'],
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ project: true,
+ tsconfigRootDir: __dirname,
+ },
+ root: true,
+ // Added lines start
+ overrides: [
+ {
+ files: ['*.js'],
+ extends: ['plugin:@typescript-eslint/disable-type-checked'],
+ },
+ ],
+ // Added lines end
+};
+```
+
+:::info
+If you use type-aware rules from other plugins, you will need to manually disable these rules or use a premade config they provide to disable them.
+:::
+
### How is performance?
Typed rules come with a catch.
diff --git a/package.json b/package.json
index f764612c05a..a031546d693 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,7 @@
"check-configs": "nx run-many --target=check-configs --parallel",
"check-docs": "nx run-many --target=check-docs --parallel",
"check-format": "prettier --list-different .",
- "check-spelling": "cspell --config=.cspell.json \"**/*.{md,mdx,ts,mts,cts,js,cjs,mjs,tsx,jsx}\"",
+ "check-spelling": "cspell --config=.cspell.json \"**/*.{md,mdx,ts,mts,cts,js,cjs,mjs,tsx,jsx}\" --no-progress --show-context --show-suggestions",
"clean": "lerna clean -y && nx run-many --target=clean",
"format": "prettier --write .",
"generate-contributors": "yarn tsx ./tools/generate-contributors.ts",
diff --git a/packages/eslint-plugin/src/configs/disable-type-checked.ts b/packages/eslint-plugin/src/configs/disable-type-checked.ts
new file mode 100644
index 00000000000..61f7e286b43
--- /dev/null
+++ b/packages/eslint-plugin/src/configs/disable-type-checked.ts
@@ -0,0 +1,53 @@
+// THIS CODE WAS AUTOMATICALLY GENERATED
+// DO NOT EDIT THIS CODE BY HAND
+// SEE https://typescript-eslint.io/linting/configs
+//
+// For developers working in the typescript-eslint monorepo:
+// You can regenerate it using `yarn generate:configs`
+
+export = {
+ parserOptions: { project: null, program: null },
+ rules: {
+ '@typescript-eslint/await-thenable': 'off',
+ '@typescript-eslint/consistent-type-exports': 'off',
+ '@typescript-eslint/dot-notation': 'off',
+ '@typescript-eslint/naming-convention': 'off',
+ '@typescript-eslint/no-base-to-string': 'off',
+ '@typescript-eslint/no-confusing-void-expression': 'off',
+ '@typescript-eslint/no-floating-promises': 'off',
+ '@typescript-eslint/no-for-in-array': 'off',
+ '@typescript-eslint/no-implied-eval': 'off',
+ '@typescript-eslint/no-meaningless-void-operator': 'off',
+ '@typescript-eslint/no-misused-promises': 'off',
+ '@typescript-eslint/no-redundant-type-constituents': 'off',
+ '@typescript-eslint/no-throw-literal': 'off',
+ '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'off',
+ '@typescript-eslint/no-unnecessary-condition': 'off',
+ '@typescript-eslint/no-unnecessary-qualifier': 'off',
+ '@typescript-eslint/no-unnecessary-type-arguments': 'off',
+ '@typescript-eslint/no-unnecessary-type-assertion': 'off',
+ '@typescript-eslint/no-unsafe-argument': 'off',
+ '@typescript-eslint/no-unsafe-assignment': 'off',
+ '@typescript-eslint/no-unsafe-call': 'off',
+ '@typescript-eslint/no-unsafe-member-access': 'off',
+ '@typescript-eslint/no-unsafe-return': 'off',
+ '@typescript-eslint/non-nullable-type-assertion-style': 'off',
+ '@typescript-eslint/prefer-includes': 'off',
+ '@typescript-eslint/prefer-nullish-coalescing': 'off',
+ '@typescript-eslint/prefer-readonly': 'off',
+ '@typescript-eslint/prefer-readonly-parameter-types': 'off',
+ '@typescript-eslint/prefer-reduce-type-parameter': 'off',
+ '@typescript-eslint/prefer-regexp-exec': 'off',
+ '@typescript-eslint/prefer-return-this-type': 'off',
+ '@typescript-eslint/prefer-string-starts-ends-with': 'off',
+ '@typescript-eslint/promise-function-async': 'off',
+ '@typescript-eslint/require-array-sort-compare': 'off',
+ '@typescript-eslint/require-await': 'off',
+ '@typescript-eslint/restrict-plus-operands': 'off',
+ '@typescript-eslint/restrict-template-expressions': 'off',
+ '@typescript-eslint/return-await': 'off',
+ '@typescript-eslint/strict-boolean-expressions': 'off',
+ '@typescript-eslint/switch-exhaustiveness-check': 'off',
+ '@typescript-eslint/unbound-method': 'off',
+ },
+};
diff --git a/packages/eslint-plugin/tools/generate-configs.ts b/packages/eslint-plugin/tools/generate-configs.ts
index 1946bee239a..7e54b6d3286 100644
--- a/packages/eslint-plugin/tools/generate-configs.ts
+++ b/packages/eslint-plugin/tools/generate-configs.ts
@@ -40,9 +40,7 @@ async function main(): Promise {
const prettierConfig = prettier.resolveConfig.sync(__dirname);
interface LinterConfigRules {
- [name: string]:
- | TSESLint.Linter.RuleLevel
- | TSESLint.Linter.RuleLevelAndOptions;
+ [name: string]: TSESLint.Linter.RuleLevel;
}
interface LinterConfig extends TSESLint.Linter.Config {
@@ -79,9 +77,11 @@ async function main(): Promise {
a[0].localeCompare(b[0]),
);
- interface ruleFilter {
+ interface RuleFilter {
deprecated?: 'exclude';
- typeChecked?: 'exclude';
+ typeChecked?: 'exclude' | 'include-only';
+ baseRuleForExtensionRule?: 'exclude';
+ forcedRuleLevel?: TSESLint.Linter.RuleLevel;
}
/**
@@ -90,7 +90,7 @@ async function main(): Promise {
function reducer(
config: LinterConfigRules,
entry: [string, TSESLint.RuleModule],
- settings: ruleFilter = {},
+ settings: RuleFilter = {},
): LinterConfigRules {
const key = entry[0];
const value = entry[1];
@@ -107,9 +107,19 @@ async function main(): Promise {
return config;
}
+ if (
+ settings.typeChecked === 'include-only' &&
+ value.meta.docs?.requiresTypeChecking !== true
+ ) {
+ return config;
+ }
+
const ruleName = `${RULE_NAME_PREFIX}${key}`;
- if (BASE_RULES_TO_BE_OVERRIDDEN.has(key)) {
+ if (
+ settings.baseRuleForExtensionRule !== 'exclude' &&
+ BASE_RULES_TO_BE_OVERRIDDEN.has(key)
+ ) {
const baseRuleName = BASE_RULES_TO_BE_OVERRIDDEN.get(key)!;
console.log(
baseRuleName
@@ -125,7 +135,7 @@ async function main(): Promise {
'=',
chalk.red('error'),
);
- config[ruleName] = 'error';
+ config[ruleName] = settings.forcedRuleLevel ?? 'error';
return config;
}
@@ -152,7 +162,7 @@ async function main(): Promise {
interface ExtendedConfigSettings {
extraExtends?: string[];
name: string;
- filters?: ruleFilter;
+ filters?: RuleFilter;
ruleEntries: RuleEntry[];
}
@@ -250,6 +260,25 @@ async function main(): Promise {
name: 'stylistic-type-checked',
ruleEntries: filterRuleEntriesTo('stylistic'),
});
+
+ writeConfig(
+ () => ({
+ parserOptions: {
+ project: null,
+ program: null,
+ },
+ rules: allRuleEntries.reduce(
+ (config, entry) =>
+ reducer(config, entry, {
+ typeChecked: 'include-only',
+ baseRuleForExtensionRule: 'exclude',
+ forcedRuleLevel: 'off',
+ }),
+ {},
+ ),
+ }),
+ 'disable-type-checked',
+ );
}
main().catch(error => {
diff --git a/packages/types/src/parser-options.ts b/packages/types/src/parser-options.ts
index f77b601e0d0..e04fd6f2534 100644
--- a/packages/types/src/parser-options.ts
+++ b/packages/types/src/parser-options.ts
@@ -51,8 +51,8 @@ interface ParserOptions {
extraFileExtensions?: string[];
filePath?: string;
loc?: boolean;
- program?: Program;
- project?: string | string[] | true;
+ program?: Program | null;
+ project?: string | string[] | true | null;
projectFolderIgnoreList?: (string | RegExp)[];
range?: boolean;
sourceType?: SourceType;
diff --git a/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts b/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts
index d3b97d6102a..3e6f7a8ac4e 100644
--- a/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts
+++ b/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts
@@ -20,12 +20,16 @@ export function getProjectConfigFiles(
ParseSettings,
'filePath' | 'tsconfigMatchCache' | 'tsconfigRootDir'
>,
- project: string | string[] | true | undefined,
-): string[] | undefined {
+ project: string | string[] | true | undefined | null,
+): string[] | null {
if (project !== true) {
- return project === undefined || Array.isArray(project)
- ? project
- : [project];
+ if (project == null) {
+ return null;
+ }
+ if (Array.isArray(project)) {
+ return project;
+ }
+ return [project];
}
log('Looking for tsconfig.json at or above file: %s', parseSettings.filePath);
diff --git a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts
index 72e9539d2b9..34e1242c5e2 100644
--- a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts
+++ b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts
@@ -27,7 +27,7 @@ let RESOLUTION_CACHE: ExpiringCache | null =
export function resolveProjectList(
options: Readonly<{
cacheLifetime?: TSESTreeOptions['cacheLifetime'];
- project: TSESTreeOptions['project'];
+ project: string[] | null;
projectFolderIgnoreList: TSESTreeOptions['projectFolderIgnoreList'];
singleRun: boolean;
tsconfigRootDir: string;
@@ -36,9 +36,7 @@ export function resolveProjectList(
const sanitizedProjects: string[] = [];
// Normalize and sanitize the project paths
- if (typeof options.project === 'string') {
- sanitizedProjects.push(options.project);
- } else if (Array.isArray(options.project)) {
+ if (options.project != null) {
for (const project of options.project) {
if (typeof project === 'string') {
sanitizedProjects.push(project);
diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts
index e9dadb48f08..742864d4e47 100644
--- a/packages/typescript-estree/src/parser-options.ts
+++ b/packages/typescript-estree/src/parser-options.ts
@@ -124,7 +124,7 @@ interface ParseAndGenerateServicesOptions extends ParseOptions {
* or `true` to find the nearest tsconfig.json to the file.
* If this is provided, type information will be returned.
*/
- project?: string | string[] | true;
+ project?: string | string[] | true | null;
/**
* If you provide a glob (or globs) to the project option, you can use this option to ignore certain folders from
@@ -145,7 +145,7 @@ interface ParseAndGenerateServicesOptions extends ParseOptions {
* This overrides any program or programs that would have been computed from the `project` option.
* All linted files must be part of the provided program(s).
*/
- programs?: ts.Program[];
+ programs?: ts.Program[] | null;
/**
* @deprecated - this flag will be removed in the next major.
diff --git a/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts b/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts
index 7378508b001..6e049c37529 100644
--- a/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts
+++ b/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts
@@ -41,7 +41,7 @@ describe('getProjectConfigFiles', () => {
const actual = getProjectConfigFiles(parseSettings, project);
- expect(actual).toEqual(project);
+ expect(actual).toBeNull();
});
describe('when caching hits', () => {