diff --git a/packages/eslint-plugin/src/rules/no-shadow.ts b/packages/eslint-plugin/src/rules/no-shadow.ts index e6ceb4f3b918..fa79c362ec50 100644 --- a/packages/eslint-plugin/src/rules/no-shadow.ts +++ b/packages/eslint-plugin/src/rules/no-shadow.ts @@ -3,7 +3,7 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { DefinitionType, ScopeType } from '@typescript-eslint/scope-manager'; import { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils'; -import { createRule } from '../util'; +import { createRule, isDefinitionFile } from '../util'; import { isTypeImport } from '../util/isTypeImport'; export type MessageIds = 'noShadow' | 'noShadowGlobal'; @@ -566,6 +566,25 @@ export default createRule({ }; } + /** + * Checks if the initialization of a variable has the declare modifier in a + * definition file. + */ + function isDeclareInDTSFile(variable: TSESLint.Scope.Variable): boolean { + const fileName = context.filename; + if (!isDefinitionFile(fileName)) { + return false; + } + return variable.defs.some(def => { + return ( + (def.type === DefinitionType.Variable && def.parent.declare) || + (def.type === DefinitionType.ClassName && def.node.declare) || + (def.type === DefinitionType.TSEnumName && def.node.declare) || + (def.type === DefinitionType.TSModuleName && def.node.declare) + ); + }); + } + /** * Checks the current context for shadowed variables. * @param scope Fixme @@ -604,6 +623,11 @@ export default createRule({ continue; } + // ignore variables with the declare keyword in .d.ts files + if (isDeclareInDTSFile(variable)) { + continue; + } + // Gets shadowed variable. const shadowed = scope.upper ? ASTUtils.findVariable(scope.upper, variable.name) diff --git a/packages/eslint-plugin/tests/rules/no-shadow/no-shadow.test.ts b/packages/eslint-plugin/tests/rules/no-shadow/no-shadow.test.ts index 22e04824b877..1378a1785ae2 100644 --- a/packages/eslint-plugin/tests/rules/no-shadow/no-shadow.test.ts +++ b/packages/eslint-plugin/tests/rules/no-shadow/no-shadow.test.ts @@ -847,6 +847,48 @@ function foo any>(fn: T, args: any[]) {} }, ], }, + { + code: ` +declare const has = (environment: 'dev' | 'prod' | 'test') => boolean; + `, + errors: [ + { + data: { + name: 'has', + }, + messageId: 'noShadowGlobal', + }, + ], + languageOptions: { + globals: { + has: false, + }, + }, + options: [{ builtinGlobals: true }], + }, + { + code: ` +declare const has: (environment: 'dev' | 'prod' | 'test') => boolean; +const fn = (has: string) => {}; + `, + errors: [ + { + data: { + name: 'has', + shadowedColumn: 15, + shadowedLine: 2, + }, + messageId: 'noShadow', + }, + ], + filename: 'foo.d.ts', + languageOptions: { + globals: { + has: false, + }, + }, + options: [{ builtinGlobals: true }], + }, ], valid: [ 'function foo any>(arg: T) {}', @@ -1455,5 +1497,134 @@ declare module 'bar' { } `, }, + { + code: ` +declare const foo1: boolean; + `, + filename: 'baz.d.ts', + languageOptions: { + globals: { + foo1: false, + }, + }, + options: [{ builtinGlobals: true }], + }, + { + code: ` +declare let foo2: boolean; + `, + filename: 'baz.d.ts', + languageOptions: { + globals: { + foo2: false, + }, + }, + options: [{ builtinGlobals: true }], + }, + { + code: ` +declare var foo3: boolean; + `, + filename: 'baz.d.ts', + languageOptions: { + globals: { + foo3: false, + }, + }, + options: [{ builtinGlobals: true }], + }, + { + code: ` +function foo4(name: string): void; + `, + filename: 'baz.d.ts', + languageOptions: { + globals: { + foo4: false, + }, + }, + options: [{ builtinGlobals: true }], + }, + { + code: ` +declare class Foopy1 { + name: string; +} + `, + filename: 'baz.d.ts', + languageOptions: { + globals: { + Foopy1: false, + }, + }, + options: [{ builtinGlobals: true }], + }, + { + code: ` +declare interface Foopy2 { + name: string; +} + `, + filename: 'baz.d.ts', + languageOptions: { + globals: { + Foopy2: false, + }, + }, + options: [{ builtinGlobals: true }], + }, + { + code: ` +declare type Foopy3 = { + x: number; +}; + `, + filename: 'baz.d.ts', + languageOptions: { + globals: { + Foopy3: false, + }, + }, + options: [{ builtinGlobals: true }], + }, + { + code: ` +declare enum Foopy4 { + x, +} + `, + filename: 'baz.d.ts', + languageOptions: { + globals: { + Foopy4: false, + }, + }, + options: [{ builtinGlobals: true }], + }, + { + code: ` +declare namespace Foopy5 {} + `, + filename: 'baz.d.ts', + languageOptions: { + globals: { + Foopy5: false, + }, + }, + options: [{ builtinGlobals: true }], + }, + { + code: ` +declare; +foo5: boolean; + `, + filename: 'baz.d.ts', + languageOptions: { + globals: { + foo5: false, + }, + }, + options: [{ builtinGlobals: true }], + }, ], });