diff --git a/.eslintrc.js b/.eslintrc.js index 4e670b5f035..6c10e3036eb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -85,7 +85,6 @@ module.exports = { '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/prefer-for-of': 'error', - '@typescript-eslint/prefer-nullish-coalescing': 'error', '@typescript-eslint/prefer-optional-chain': 'error', '@typescript-eslint/unbound-method': 'off', '@typescript-eslint/prefer-as-const': 'error', diff --git a/packages/ast-spec/tests/util/serialize-error.ts b/packages/ast-spec/tests/util/serialize-error.ts index ee8597c6148..5906c6e0ee7 100644 --- a/packages/ast-spec/tests/util/serialize-error.ts +++ b/packages/ast-spec/tests/util/serialize-error.ts @@ -2,10 +2,7 @@ import { codeFrameColumns } from '@babel/code-frame'; import { TSError } from './parsers/typescript-estree-import'; -export function serializeError( - error: unknown, - contents: string, -): unknown | string { +export function serializeError(error: unknown, contents: string): unknown { if (!(error instanceof TSError)) { return error; } diff --git a/packages/eslint-plugin/src/configs/recommended-type-checked.ts b/packages/eslint-plugin/src/configs/recommended-type-checked.ts index 27c128ec3c0..6be755c48e7 100644 --- a/packages/eslint-plugin/src/configs/recommended-type-checked.ts +++ b/packages/eslint-plugin/src/configs/recommended-type-checked.ts @@ -13,7 +13,9 @@ export = { '@typescript-eslint/ban-types': 'error', 'no-array-constructor': 'off', '@typescript-eslint/no-array-constructor': 'error', + '@typescript-eslint/no-base-to-string': 'error', '@typescript-eslint/no-duplicate-enum-values': 'error', + '@typescript-eslint/no-duplicate-type-constituents': 'error', '@typescript-eslint/no-extra-non-null-assertion': 'error', '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-for-in-array': 'error', @@ -25,12 +27,15 @@ export = { '@typescript-eslint/no-misused-promises': 'error', '@typescript-eslint/no-namespace': 'error', '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', + '@typescript-eslint/no-redundant-type-constituents': 'error', '@typescript-eslint/no-this-alias': 'error', '@typescript-eslint/no-unnecessary-type-assertion': 'error', '@typescript-eslint/no-unnecessary-type-constraint': 'error', '@typescript-eslint/no-unsafe-argument': 'error', '@typescript-eslint/no-unsafe-assignment': 'error', '@typescript-eslint/no-unsafe-call': 'error', + '@typescript-eslint/no-unsafe-declaration-merging': 'error', + '@typescript-eslint/no-unsafe-enum-comparison': 'error', '@typescript-eslint/no-unsafe-member-access': 'error', '@typescript-eslint/no-unsafe-return': 'error', 'no-unused-vars': 'off', diff --git a/packages/eslint-plugin/src/configs/recommended.ts b/packages/eslint-plugin/src/configs/recommended.ts index 3c2ec73e265..0f817d7681b 100644 --- a/packages/eslint-plugin/src/configs/recommended.ts +++ b/packages/eslint-plugin/src/configs/recommended.ts @@ -21,6 +21,7 @@ export = { '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', '@typescript-eslint/no-this-alias': 'error', '@typescript-eslint/no-unnecessary-type-constraint': 'error', + '@typescript-eslint/no-unsafe-declaration-merging': 'error', 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'error', '@typescript-eslint/no-var-requires': 'error', diff --git a/packages/eslint-plugin/src/configs/strict-type-checked.ts b/packages/eslint-plugin/src/configs/strict-type-checked.ts index 77b844e0944..b666e4f1cb6 100644 --- a/packages/eslint-plugin/src/configs/strict-type-checked.ts +++ b/packages/eslint-plugin/src/configs/strict-type-checked.ts @@ -15,6 +15,7 @@ export = { '@typescript-eslint/no-array-constructor': 'error', '@typescript-eslint/no-base-to-string': 'error', '@typescript-eslint/no-duplicate-enum-values': 'error', + '@typescript-eslint/no-duplicate-type-constituents': 'error', '@typescript-eslint/no-dynamic-delete': 'error', '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/no-extra-non-null-assertion': 'error', @@ -34,6 +35,7 @@ export = { '@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error', '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', '@typescript-eslint/no-non-null-assertion': 'error', + '@typescript-eslint/no-redundant-type-constituents': 'error', '@typescript-eslint/no-this-alias': 'error', 'no-throw-literal': 'off', '@typescript-eslint/no-throw-literal': 'error', diff --git a/packages/eslint-plugin/src/configs/stylistic-type-checked.ts b/packages/eslint-plugin/src/configs/stylistic-type-checked.ts index 9ce234d4676..ed9e23dae4a 100644 --- a/packages/eslint-plugin/src/configs/stylistic-type-checked.ts +++ b/packages/eslint-plugin/src/configs/stylistic-type-checked.ts @@ -19,6 +19,7 @@ export = { 'dot-notation': 'off', '@typescript-eslint/dot-notation': 'error', '@typescript-eslint/no-confusing-non-null-assertion': 'error', + '@typescript-eslint/no-confusing-void-expression': 'error', 'no-empty-function': 'off', '@typescript-eslint/no-empty-function': 'error', '@typescript-eslint/no-empty-interface': 'error', diff --git a/packages/eslint-plugin/src/index.ts b/packages/eslint-plugin/src/index.ts index 57ee2008bda..ece2bb0a20f 100644 --- a/packages/eslint-plugin/src/index.ts +++ b/packages/eslint-plugin/src/index.ts @@ -17,6 +17,7 @@ export = { 'disable-type-checked': disableTypeChecked, 'eslint-recommended': eslintRecommended, recommended, + /** @deprecated - please use "recommended-type-checked" instead. */ 'recommended-requiring-type-checking': recommendedTypeChecked, 'recommended-type-checked': recommendedTypeChecked, strict, diff --git a/packages/eslint-plugin/src/rules/consistent-type-exports.ts b/packages/eslint-plugin/src/rules/consistent-type-exports.ts index 97b7d9c0504..0a3b7b93dee 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-exports.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-exports.ts @@ -84,6 +84,7 @@ export default util.createRule({ const symbol = services.getSymbolAtLocation(specifier.exported); const aliasedSymbol = checker.getAliasedSymbol(symbol!); + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison if (!aliasedSymbol || aliasedSymbol.escapedName === 'unknown') { return undefined; } diff --git a/packages/eslint-plugin/src/rules/no-base-to-string.ts b/packages/eslint-plugin/src/rules/no-base-to-string.ts index eedb18b516e..9d74c87117c 100644 --- a/packages/eslint-plugin/src/rules/no-base-to-string.ts +++ b/packages/eslint-plugin/src/rules/no-base-to-string.ts @@ -5,7 +5,7 @@ import * as ts from 'typescript'; import * as util from '../util'; enum Usefulness { - Always, + Always = 'always', Never = 'will', Sometimes = 'may', } @@ -23,7 +23,7 @@ export default util.createRule({ docs: { description: 'Require `.toString()` to only be called on objects which provide useful information when stringified', - recommended: 'strict', + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts index 601e13f9475..1a2b81b9f8f 100644 --- a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts +++ b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts @@ -28,6 +28,7 @@ export default util.createRule({ docs: { description: 'Require expressions of type void to appear in statement position', + recommended: 'stylistic', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-duplicate-type-constituents.ts b/packages/eslint-plugin/src/rules/no-duplicate-type-constituents.ts index 0a0d515e6db..85135d5c7c5 100644 --- a/packages/eslint-plugin/src/rules/no-duplicate-type-constituents.ts +++ b/packages/eslint-plugin/src/rules/no-duplicate-type-constituents.ts @@ -73,6 +73,7 @@ export default util.createRule({ docs: { description: 'Disallow duplicate constituents of union or intersection types', + recommended: 'recommended', requiresTypeChecking: true, }, fixable: 'code', diff --git a/packages/eslint-plugin/src/rules/no-empty-interface.ts b/packages/eslint-plugin/src/rules/no-empty-interface.ts index d44a92eb908..12499f3b95c 100644 --- a/packages/eslint-plugin/src/rules/no-empty-interface.ts +++ b/packages/eslint-plugin/src/rules/no-empty-interface.ts @@ -1,3 +1,4 @@ +import { ScopeType } from '@typescript-eslint/scope-manager'; import type { TSESLint } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; @@ -84,7 +85,7 @@ export default util.createRule({ const isInAmbientDeclaration = !!( util.isDefinitionFile(filename) && - scope.type === 'tsModule' && + scope.type === ScopeType.tsModule && scope.block.declare ); diff --git a/packages/eslint-plugin/src/rules/no-implied-eval.ts b/packages/eslint-plugin/src/rules/no-implied-eval.ts index 1da7114a0d4..9c4a83b5d1b 100644 --- a/packages/eslint-plugin/src/rules/no-implied-eval.ts +++ b/packages/eslint-plugin/src/rules/no-implied-eval.ts @@ -77,6 +77,7 @@ export default util.createRule({ return true; } + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison if (symbol && symbol.escapedName === FUNCTION_CONSTRUCTOR) { const declarations = symbol.getDeclarations() ?? []; for (const declaration of declarations) { diff --git a/packages/eslint-plugin/src/rules/no-redeclare.ts b/packages/eslint-plugin/src/rules/no-redeclare.ts index 395a9e5b1bc..3591895fa57 100644 --- a/packages/eslint-plugin/src/rules/no-redeclare.ts +++ b/packages/eslint-plugin/src/rules/no-redeclare.ts @@ -1,3 +1,4 @@ +import { ScopeType } from '@typescript-eslint/scope-manager'; import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; @@ -255,7 +256,7 @@ export default util.createRule({ // Node.js or ES modules has a special scope. if ( - scope.type === 'global' && + scope.type === ScopeType.global && scope.childScopes[0] && // The special scope's block is the Program node. scope.block === scope.childScopes[0].block diff --git a/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts b/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts index 9572df39dea..e70637256bf 100644 --- a/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts +++ b/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts @@ -87,6 +87,7 @@ function describeLiteralType(type: ts.Type): string { } if (type.isLiteral()) { + // eslint-disable-next-line @typescript-eslint/no-base-to-string return type.value.toString(); } @@ -182,6 +183,7 @@ export default util.createRule({ docs: { description: 'Disallow members of unions and intersections that do nothing or override type information', + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-shadow.ts b/packages/eslint-plugin/src/rules/no-shadow.ts index f40ea991dba..461d5cb6016 100644 --- a/packages/eslint-plugin/src/rules/no-shadow.ts +++ b/packages/eslint-plugin/src/rules/no-shadow.ts @@ -365,7 +365,7 @@ export default util.createRule({ ): TSESLint.Scope.Scope | null { const upper = scope.upper; - if (upper?.type === 'function-expression-name') { + if (upper?.type === ScopeType.functionExpressionName) { return upper.upper; } return upper; diff --git a/packages/eslint-plugin/src/rules/no-unsafe-declaration-merging.ts b/packages/eslint-plugin/src/rules/no-unsafe-declaration-merging.ts index 89d68db6e67..3e034ba458a 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-declaration-merging.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-declaration-merging.ts @@ -10,7 +10,7 @@ export default util.createRule({ type: 'problem', docs: { description: 'Disallow unsafe declaration merging', - recommended: 'strict', + recommended: 'recommended', requiresTypeChecking: false, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-unsafe-enum-comparison.ts b/packages/eslint-plugin/src/rules/no-unsafe-enum-comparison.ts index 80b610d751e..0a068b577e7 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-enum-comparison.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-enum-comparison.ts @@ -42,7 +42,7 @@ export default util.createRule({ type: 'suggestion', docs: { description: 'Disallow comparing an enum value with a non-enum value', - recommended: 'strict', + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts index 39bee570147..9d01f3af026 100644 --- a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts +++ b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts @@ -63,9 +63,9 @@ export default util.createRule({ }, defaultOptions: [ { - ignoreConditionalTests: true, - ignoreTernaryTests: true, - ignoreMixedLogicalExpressions: true, + ignoreConditionalTests: false, + ignoreTernaryTests: false, + ignoreMixedLogicalExpressions: false, allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: false, }, ], diff --git a/packages/eslint-plugin/src/rules/require-array-sort-compare.ts b/packages/eslint-plugin/src/rules/require-array-sort-compare.ts index f5628120c80..a3617894ee7 100644 --- a/packages/eslint-plugin/src/rules/require-array-sort-compare.ts +++ b/packages/eslint-plugin/src/rules/require-array-sort-compare.ts @@ -13,7 +13,7 @@ export default util.createRule({ name: 'require-array-sort-compare', defaultOptions: [ { - ignoreStringArrays: false, + ignoreStringArrays: true, }, ], diff --git a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts index 4609499e38a..6d2cc2222ea 100644 --- a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts +++ b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts @@ -72,6 +72,11 @@ export default util.createRule({ }, defaultOptions: [ { + allowAny: true, + allowBoolean: true, + allowNullish: true, + allowNumberAndString: true, + allowRegExp: true, skipCompoundAssignments: false, }, ], @@ -79,12 +84,12 @@ export default util.createRule({ context, [ { - skipCompoundAssignments, allowAny, allowBoolean, allowNullish, allowNumberAndString, allowRegExp, + skipCompoundAssignments, }, ], ) { diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index 42a3a39e3ca..5da963a8219 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -71,7 +71,11 @@ export default util.createRule({ }, defaultOptions: [ { + allowAny: true, + allowBoolean: true, + allowNullish: true, allowNumber: true, + allowRegExp: true, }, ], create(context, [options]) { diff --git a/packages/eslint-plugin/src/rules/unbound-method.ts b/packages/eslint-plugin/src/rules/unbound-method.ts index 73439efc5fd..f3cc2b71185 100644 --- a/packages/eslint-plugin/src/rules/unbound-method.ts +++ b/packages/eslint-plugin/src/rules/unbound-method.ts @@ -271,6 +271,7 @@ function checkMethod( const firstParam = decl.parameters[0]; const firstParamIsThis = firstParam?.name.kind === ts.SyntaxKind.Identifier && + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison firstParam?.name.escapedText === 'this'; const thisArgIsVoid = firstParamIsThis && diff --git a/packages/eslint-plugin/src/util/collectUnusedVariables.ts b/packages/eslint-plugin/src/util/collectUnusedVariables.ts index a0ad2676a01..4d1b62b4234 100644 --- a/packages/eslint-plugin/src/util/collectUnusedVariables.ts +++ b/packages/eslint-plugin/src/util/collectUnusedVariables.ts @@ -1,4 +1,8 @@ -import { ImplicitLibVariable, Visitor } from '@typescript-eslint/scope-manager'; +import { + ImplicitLibVariable, + ScopeType, + Visitor, +} from '@typescript-eslint/scope-manager'; import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, @@ -97,7 +101,7 @@ class UnusedVarsVisitor< const scope = this.#scopeManager.acquire(node, inner); if (scope) { - if (scope.type === 'function-expression-name') { + if (scope.type === ScopeType.functionExpressionName) { return scope.childScopes[0] as T; } return scope as T; diff --git a/packages/eslint-plugin/tests/rules/require-array-sort-compare.test.ts b/packages/eslint-plugin/tests/rules/require-array-sort-compare.test.ts index 99326816468..771adedb141 100644 --- a/packages/eslint-plugin/tests/rules/require-array-sort-compare.test.ts +++ b/packages/eslint-plugin/tests/rules/require-array-sort-compare.test.ts @@ -138,12 +138,29 @@ ruleTester.run('require-array-sort-compare', rule, { }, { code: ` - function f(a: string[]) { + function f(a: number[]) { a.sort(); } `, errors: [{ messageId: 'requireCompare' }], }, + { + code: ` + function f(a: number[]) { + a.sort(); + } + `, + errors: [{ messageId: 'requireCompare' }], + options: [{ ignoreStringArrays: false }], + }, + { + code: ` + function f(a: number | number[]) { + if (Array.isArray(a)) a.sort(); + } + `, + errors: [{ messageId: 'requireCompare' }], + }, { code: ` function f(a: string | string[]) { @@ -151,6 +168,7 @@ ruleTester.run('require-array-sort-compare', rule, { } `, errors: [{ messageId: 'requireCompare' }], + options: [{ ignoreStringArrays: false }], }, { code: ` @@ -179,7 +197,7 @@ ruleTester.run('require-array-sort-compare', rule, { // optional chain { code: ` - function f(a: string[]) { + function f(a: number[]) { a?.sort(); } `, @@ -187,24 +205,24 @@ ruleTester.run('require-array-sort-compare', rule, { }, { code: ` - ['foo', 'bar', 'baz'].sort(); + [1, 2, 3].sort(); `, errors: [{ messageId: 'requireCompare' }], }, { code: ` - function getString() { - return 'foo'; + function getNumber() { + return 1; } - [getString(), getString()].sort(); + [getNumber(), getNumber()].sort(); `, errors: [{ messageId: 'requireCompare' }], }, { code: ` - const foo = 'foo'; - const bar = 'bar'; - const baz = 'baz'; + const foo = 1; + const bar = 2; + const baz = 3; [foo, bar, baz].sort(); `, errors: [{ messageId: 'requireCompare' }], diff --git a/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts b/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts index 8979d4dc1e0..f98f6c18750 100644 --- a/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts +++ b/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts @@ -177,7 +177,11 @@ const x = a + b; `, options: [ { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, allowRegExp: true, + allowNullish: false, }, ], }, @@ -189,7 +193,11 @@ const x = a + b; `, options: [ { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, allowRegExp: true, + allowNullish: false, }, ], }, @@ -244,6 +252,11 @@ foo += 0; `, options: [ { + allowAny: false, + allowBoolean: false, + allowNullish: false, + allowNumberAndString: false, + allowRegExp: false, skipCompoundAssignments: true, }, ], @@ -255,6 +268,11 @@ foo += ''; `, options: [ { + allowAny: false, + allowBoolean: false, + allowNullish: false, + allowNumberAndString: false, + allowRegExp: false, skipCompoundAssignments: true, }, ], @@ -354,6 +372,23 @@ const f = (a: string | number, b: string | number) => a + b; }, ], invalid: [ + { + code: "let foo = '1' + 1;", + errors: [ + { + data: { + left: 'string', + right: 'number', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', + }, + messageId: 'mismatched', + line: 1, + column: 11, + }, + ], + options: [{ allowNumberAndString: false }], + }, { code: "let foo = '1' + 1;", errors: [ @@ -368,13 +403,23 @@ const f = (a: string | number, b: string | number) => a + b; column: 11, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNullish: false, + allowNumberAndString: false, + allowRegExp: false, + }, + ], }, { code: 'let foo = [] + {};', errors: [ { data: { - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', type: 'never[]', }, column: 11, @@ -384,7 +429,8 @@ const f = (a: string | number, b: string | number) => a + b; }, { data: { - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', type: '{}', }, column: 16, @@ -408,13 +454,23 @@ const f = (a: string | number, b: string | number) => a + b; column: 11, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNullish: false, + allowNumberAndString: false, + allowRegExp: false, + }, + ], }, { code: 'let foo = [] + 5;', errors: [ { data: { - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', type: 'never[]', }, messageId: 'invalid', @@ -429,7 +485,8 @@ const f = (a: string | number, b: string | number) => a + b; errors: [ { data: { - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', type: 'never[]', }, messageId: 'invalid', @@ -439,7 +496,8 @@ const f = (a: string | number, b: string | number) => a + b; }, { data: { - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', type: 'never[]', }, messageId: 'invalid', @@ -454,7 +512,8 @@ const f = (a: string | number, b: string | number) => a + b; errors: [ { data: { - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', type: 'number[]', }, column: 15, @@ -469,7 +528,8 @@ const f = (a: string | number, b: string | number) => a + b; errors: [ { data: { - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', type: '{}', }, messageId: 'invalid', @@ -486,13 +546,15 @@ const f = (a: string | number, b: string | number) => a + b; data: { left: 'number', right: 'string', - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', }, messageId: 'mismatched', line: 1, column: 11, }, ], + options: [{ allowNumberAndString: false }], }, { code: "let foo = '5.5' + 5;", @@ -501,13 +563,15 @@ const f = (a: string | number, b: string | number) => a + b; data: { left: 'string', right: 'number', - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', }, messageId: 'mismatched', line: 1, column: 11, }, ], + options: [{ allowNumberAndString: false }], }, { code: ` @@ -520,13 +584,15 @@ let foo = x + y; data: { left: 'number', right: 'string', - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', }, messageId: 'mismatched', line: 4, column: 11, }, ], + options: [{ allowNumberAndString: false }], }, { code: ` @@ -539,13 +605,15 @@ let foo = y + x; data: { right: 'number', left: 'string', - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', }, messageId: 'mismatched', line: 4, column: 11, }, ], + options: [{ allowNumberAndString: false }], }, { code: ` @@ -555,7 +623,8 @@ let foo = x + {}; errors: [ { data: { - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', type: '{}', }, messageId: 'invalid', @@ -572,7 +641,8 @@ let foo = [] + y; errors: [ { data: { - stringLike: 'string', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', type: 'never[]', }, messageId: 'invalid', @@ -608,6 +678,15 @@ let foo = pair + pair; messageId: 'invalid', }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -627,6 +706,15 @@ let combined = value + 0; messageId: 'invalid', }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: 'let foo = 1n + 1;', @@ -709,6 +797,15 @@ function foo(a: T) { column: 10, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -728,6 +825,15 @@ function foo(a: T) { column: 10, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -747,6 +853,15 @@ function foo(a: T) { column: 10, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -766,6 +881,15 @@ function foo(a: T) { column: 10, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -785,6 +909,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -803,6 +936,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -821,6 +963,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -839,6 +990,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -857,6 +1017,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -875,6 +1044,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -896,6 +1074,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -920,6 +1107,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -939,6 +1135,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -957,6 +1162,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -975,6 +1189,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -993,6 +1216,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -1011,6 +1243,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -1029,6 +1270,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -1047,6 +1297,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -1065,6 +1324,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -1083,6 +1351,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -1101,6 +1378,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -1119,6 +1405,15 @@ function foo(a: T) { column: 19, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -1127,6 +1422,11 @@ foo += 'some data'; `, options: [ { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, skipCompoundAssignments: false, }, ], @@ -1158,6 +1458,15 @@ foo += 'some data'; column: 1, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNumberAndString: false, + allowRegExp: false, + allowNullish: false, + }, + ], }, { code: ` @@ -1176,6 +1485,15 @@ foo += 1; column: 1, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNullish: false, + allowNumberAndString: false, + allowRegExp: false, + }, + ], }, { code: ` @@ -1194,6 +1512,15 @@ foo += ''; column: 1, }, ], + options: [ + { + allowAny: false, + allowBoolean: false, + allowNullish: false, + allowNumberAndString: false, + allowRegExp: false, + }, + ], }, { code: ` @@ -1202,6 +1529,7 @@ const f = (a: any, b: boolean) => a + b; options: [ { allowAny: true, + allowBoolean: false, }, ], errors: [ @@ -1224,7 +1552,8 @@ const f = (a: any, b: []) => a + b; errors: [ { data: { - stringLike: 'string, allowing a string + `any`', + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', type: '[]', }, messageId: 'invalid', @@ -1239,13 +1568,15 @@ const f = (a: any, b: boolean) => a + b; `, options: [ { + allowAny: false, allowBoolean: true, }, ], errors: [ { data: { - stringLike: 'string, allowing a string + `boolean`', + stringLike: + 'string, allowing a string + any of: `boolean`, `null`, `RegExp`, `undefined`', type: 'any', }, messageId: 'invalid', @@ -1346,6 +1677,7 @@ const f = (a: any, b: boolean) => a + b; options: [ { allowAny: false, + allowBoolean: false, }, ], }, @@ -1375,7 +1707,7 @@ foo = foo + 'some data'; { data: { stringLike: - 'string, allowing a string + any of: `null`, `undefined`', + 'string, allowing a string + any of: `any`, `null`, `RegExp`, `undefined`', type: 'string | boolean', }, messageId: 'invalid', @@ -1385,7 +1717,7 @@ foo = foo + 'some data'; ], options: [ { - allowNullish: true, + allowBoolean: false, }, ], }, @@ -1398,7 +1730,7 @@ foo = foo + 'some data'; { data: { stringLike: - 'string, allowing a string + any of: `null`, `undefined`', + 'string, allowing a string + any of: `any`, `null`, `RegExp`, `undefined`', type: 'boolean', }, messageId: 'invalid', @@ -1408,7 +1740,7 @@ foo = foo + 'some data'; ], options: [ { - allowNullish: true, + allowBoolean: false, }, ], }, diff --git a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts index 7e3a4858f3a..48b700584ef 100644 --- a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts +++ b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts @@ -291,6 +291,11 @@ ruleTester.run('restrict-template-expressions', rule, { } `, }, + 'const msg = `arg = ${false}`;', + 'const msg = `arg = ${null}`;', + 'const msg = `arg = ${undefined}`;', + 'const msg = `arg = ${123}`;', + "const msg = `arg = ${'abc'}`;", ], invalid: [ @@ -320,6 +325,7 @@ ruleTester.run('restrict-template-expressions', rule, { column: 30, }, ], + options: [{ allowBoolean: false }], }, { code: ` @@ -333,6 +339,7 @@ ruleTester.run('restrict-template-expressions', rule, { column: 30, }, ], + options: [{ allowNullish: false }], }, { code: ` @@ -362,6 +369,11 @@ ruleTester.run('restrict-template-expressions', rule, { column: 30, }, ], + options: [ + { + allowBoolean: false, + }, + ], }, { options: [{ allowNumber: true, allowBoolean: true, allowNullish: true }], @@ -399,7 +411,14 @@ ruleTester.run('restrict-template-expressions', rule, { ], }, { - options: [{ allowNumber: true, allowBoolean: true, allowNullish: true }], + options: [ + { + allowAny: false, + allowNumber: true, + allowBoolean: true, + allowNullish: true, + }, + ], code: ` function test(arg: T) { return \`arg = \${arg}\`; @@ -420,7 +439,14 @@ ruleTester.run('restrict-template-expressions', rule, { ], }, { - options: [{ allowNumber: true, allowBoolean: true, allowNullish: true }], + options: [ + { + allowAny: false, + allowNumber: true, + allowBoolean: true, + allowNullish: true, + }, + ], code: ` function test(arg: any) { return \`arg = \${arg}\`; diff --git a/packages/rule-tester/src/RuleTester.ts b/packages/rule-tester/src/RuleTester.ts index 0ff658adfbd..cf2b394d716 100644 --- a/packages/rule-tester/src/RuleTester.ts +++ b/packages/rule-tester/src/RuleTester.ts @@ -196,9 +196,7 @@ export class RuleTester extends TestFramework { : this.#testerConfig.defaultFilenames.ts; if (resolvedOptions.project) { return path.join( - resolvedOptions.tsconfigRootDir != null - ? resolvedOptions.tsconfigRootDir - : process.cwd(), + resolvedOptions.tsconfigRootDir ?? process.cwd(), filename, ); } diff --git a/packages/scope-manager/src/ScopeManager.ts b/packages/scope-manager/src/ScopeManager.ts index 2e8e469a26c..e6d3ee333c3 100644 --- a/packages/scope-manager/src/ScopeManager.ts +++ b/packages/scope-manager/src/ScopeManager.ts @@ -14,6 +14,7 @@ import { GlobalScope, MappedTypeScope, ModuleScope, + ScopeType, SwitchScope, TSEnumScope, TSModuleScope, @@ -109,7 +110,10 @@ class ScopeManager { */ public acquire(node: TSESTree.Node, inner = false): Scope | null { function predicate(testScope: Scope): boolean { - if (testScope.type === 'function' && testScope.functionExpressionScope) { + if ( + testScope.type === ScopeType.function && + testScope.functionExpressionScope + ) { return false; } return true; diff --git a/packages/type-utils/src/TypeOrValueSpecifier.ts b/packages/type-utils/src/TypeOrValueSpecifier.ts index 9d568b010aa..0230f911dfb 100644 --- a/packages/type-utils/src/TypeOrValueSpecifier.ts +++ b/packages/type-utils/src/TypeOrValueSpecifier.ts @@ -126,7 +126,7 @@ function specifierNameMatches(type: ts.Type, name: string | string[]): boolean { if (symbol === undefined) { return false; } - return name.some(item => item === symbol.escapedName); + return name.some(item => (item as ts.__String) === symbol.escapedName); } function typeDeclaredInFile( diff --git a/packages/type-utils/src/isTypeReadonly.ts b/packages/type-utils/src/isTypeReadonly.ts index 63a02ea4464..9fc8d7c6216 100644 --- a/packages/type-utils/src/isTypeReadonly.ts +++ b/packages/type-utils/src/isTypeReadonly.ts @@ -86,6 +86,7 @@ function isTypeReadonlyArrayOrTuple( ESLintUtils.NullThrowsReasons.MissingToken('symbol', 'array type'), ); const escapedName = symbol.getEscapedName(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison if (escapedName === 'Array') { return Readonlyness.Mutable; } diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 0a10359d41d..1db8c1c00e6 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -227,7 +227,7 @@ export class Converter { * @param parent parentNode * @returns the converted ESTree node */ - private convertPattern(child?: ts.Node, parent?: ts.Node): any | null { + private convertPattern(child?: ts.Node, parent?: ts.Node): any { return this.converter(child, parent, true); } @@ -237,7 +237,7 @@ export class Converter { * @param parent parentNode * @returns the converted ESTree node */ - private convertChild(child?: ts.Node, parent?: ts.Node): any | null { + private convertChild(child?: ts.Node, parent?: ts.Node): any { return this.converter(child, parent, false); } @@ -1310,7 +1310,7 @@ export class Converter { case SyntaxKind.Constructor: { const lastModifier = getLastModifier(node); const constructorToken = - (lastModifier && findNextToken(lastModifier, node, this.ast)) || + (lastModifier && findNextToken(lastModifier, node, this.ast)) ?? node.getFirstToken()!; const constructor = this.createNode< diff --git a/packages/typescript-estree/tools/test-utils.ts b/packages/typescript-estree/tools/test-utils.ts index 5c3bc2f990a..81121274b25 100644 --- a/packages/typescript-estree/tools/test-utils.ts +++ b/packages/typescript-estree/tools/test-utils.ts @@ -84,7 +84,7 @@ export function deeplyCopy(ast: T): T { type UnknownObject = Record; -function isObjectLike(value: unknown | null): value is UnknownObject { +function isObjectLike(value: unknown): value is UnknownObject { return ( typeof value === 'object' && !(value instanceof RegExp) && value != null ); diff --git a/packages/utils/src/eslint-utils/deepMerge.ts b/packages/utils/src/eslint-utils/deepMerge.ts index 9b7baee5ebb..9d275ecfc61 100644 --- a/packages/utils/src/eslint-utils/deepMerge.ts +++ b/packages/utils/src/eslint-utils/deepMerge.ts @@ -5,9 +5,7 @@ type ObjectLike = Record; * @param obj an object * @returns `true` if obj is an object */ -function isObjectNotArray( - obj: unknown | unknown[], -): obj is T { +function isObjectNotArray(obj: unknown): obj is T { return typeof obj === 'object' && !Array.isArray(obj); } diff --git a/packages/website/src/components/lib/debounce.ts b/packages/website/src/components/lib/debounce.ts index 87feff49f65..8e4b40ee193 100644 --- a/packages/website/src/components/lib/debounce.ts +++ b/packages/website/src/components/lib/debounce.ts @@ -3,7 +3,7 @@ export function debounce( wait: number, ): (...args: X) => void { // eslint-disable-next-line @typescript-eslint/no-explicit-any - let timeout: any | undefined; + let timeout: any; return function (...args: X): void { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument clearTimeout(timeout); diff --git a/packages/website/src/components/linter/utils.ts b/packages/website/src/components/linter/utils.ts index c26197f6cab..2f6f59f9c14 100644 --- a/packages/website/src/components/linter/utils.ts +++ b/packages/website/src/components/linter/utils.ts @@ -17,7 +17,7 @@ export function ensurePositiveInt( value: number | undefined, defaultValue: number, ): number { - return Math.max(1, (value !== undefined ? value : defaultValue) | 0); + return Math.max(1, (value ?? defaultValue) | 0); } export function createURI(marker: Monaco.editor.IMarkerData): string {