diff --git a/packages/eslint-plugin/src/rules/no-extra-parens.ts b/packages/eslint-plugin/src/rules/no-extra-parens.ts index 42fd53d3310..10989ad47e8 100644 --- a/packages/eslint-plugin/src/rules/no-extra-parens.ts +++ b/packages/eslint-plugin/src/rules/no-extra-parens.ts @@ -164,23 +164,7 @@ export default util.createRule({ return rules.ConditionalExpression(node); }, // DoWhileStatement - 'ForInStatement, ForOfStatement'( - node: TSESTree.ForInStatement | TSESTree.ForOfStatement, - ) { - if (util.isTypeAssertion(node.right)) { - // makes the rule skip checking of the right - return rules['ForInStatement, ForOfStatement']({ - ...node, - type: AST_NODE_TYPES.ForOfStatement as any, - right: { - ...node.right, - type: AST_NODE_TYPES.SequenceExpression as any, - }, - }); - } - - return rules['ForInStatement, ForOfStatement'](node); - }, + // ForIn and ForOf are guarded by eslint version ForStatement(node) { // make the rule skip the piece by removing it entirely if (node.init && util.isTypeAssertion(node.init)) { @@ -256,6 +240,56 @@ export default util.createRule({ } }, }; + if (rules.ForInStatement && rules.ForOfStatement) { + overrides.ForInStatement = function (node): void { + if (util.isTypeAssertion(node.right)) { + // makes the rule skip checking of the right + return rules.ForInStatement({ + ...node, + type: AST_NODE_TYPES.ForInStatement, + right: { + ...node.right, + type: AST_NODE_TYPES.SequenceExpression as any, + }, + }); + } + + return rules.ForInStatement(node); + }; + overrides.ForOfStatement = function (node): void { + if (util.isTypeAssertion(node.right)) { + // makes the rule skip checking of the right + return rules.ForOfStatement({ + ...node, + type: AST_NODE_TYPES.ForOfStatement, + right: { + ...node.right, + type: AST_NODE_TYPES.SequenceExpression as any, + }, + }); + } + + return rules.ForOfStatement(node); + }; + } else { + overrides['ForInStatement, ForOfStatement'] = function ( + node: TSESTree.ForInStatement | TSESTree.ForOfStatement, + ): void { + if (util.isTypeAssertion(node.right)) { + // makes the rule skip checking of the right + return rules['ForInStatement, ForOfStatement']({ + ...node, + type: AST_NODE_TYPES.ForOfStatement as any, + right: { + ...node.right, + type: AST_NODE_TYPES.SequenceExpression as any, + }, + }); + } + + return rules['ForInStatement, ForOfStatement'](node); + }; + } return Object.assign({}, rules, overrides); }, }); diff --git a/packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts b/packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts index c7cd5aeb399..020a4e715d6 100644 --- a/packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts +++ b/packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts @@ -235,6 +235,10 @@ declare function deco(...param: any): (...param: any) => any; }) class Foo {} `, + // https://github.com/typescript-eslint/typescript-eslint/issues/3006 + ` +export type AppState = typeof import('./src/store/reducers').default; + `, ], invalid: [ { diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 49e48541f87..425956e1f25 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -520,9 +520,13 @@ declare module 'eslint/lib/rules/no-extra-parens' { ClassExpression(node: TSESTree.ClassExpression): void; ConditionalExpression(node: TSESTree.ConditionalExpression): void; DoWhileStatement(node: TSESTree.DoWhileStatement): void; + // eslint < 7.19.0 'ForInStatement, ForOfStatement'( node: TSESTree.ForInStatement | TSESTree.ForOfStatement, ): void; + // eslint >= 7.19.0 + ForInStatement(node: TSESTree.ForInStatement): void; + ForOfStatement(node: TSESTree.ForOfStatement): void; ForStatement(node: TSESTree.ForStatement): void; 'ForStatement > *.init:exit'(node: TSESTree.Node): void; IfStatement(node: TSESTree.IfStatement): void; diff --git a/packages/scope-manager/src/referencer/TypeVisitor.ts b/packages/scope-manager/src/referencer/TypeVisitor.ts index 155aea5c5d9..e9abb40f4f4 100644 --- a/packages/scope-manager/src/referencer/TypeVisitor.ts +++ b/packages/scope-manager/src/referencer/TypeVisitor.ts @@ -116,6 +116,12 @@ class TypeVisitor extends Visitor { this.visitFunctionType(node); } + protected TSImportType(node: TSESTree.TSImportType): void { + // the TS parser allows any type to be the parameter, but it's a syntax error - so we can ignore it + this.visit(node.typeParameters); + // the qualifier is just part of a standard EntityName, so it should not be visited + } + protected TSIndexSignature(node: TSESTree.TSIndexSignature): void { for (const param of node.parameters) { if (param.type === AST_NODE_TYPES.Identifier) { diff --git a/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-qualifier.ts b/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-qualifier.ts new file mode 100644 index 00000000000..b67f291d115 --- /dev/null +++ b/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-qualifier.ts @@ -0,0 +1 @@ +type T = import('').default; diff --git a/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-qualifier.ts.shot b/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-qualifier.ts.shot new file mode 100644 index 00000000000..25e42ebd08b --- /dev/null +++ b/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-qualifier.ts.shot @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`type-declaration import-type-with-qualifier 1`] = ` +ScopeManager { + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2 { + defs: Array [ + TypeDefinition$1 { + name: Identifier<"T">, + node: TSTypeAliasDeclaration$1, + }, + ], + name: "T", + references: Array [], + isValueVariable: false, + isTypeVariable: true, + }, + ], + scopes: Array [ + GlobalScope$1 { + block: Program$2, + isStrict: false, + references: Array [], + set: Map { + "const" => ImplicitGlobalConstTypeVariable, + "T" => Variable$2, + }, + type: "global", + upper: null, + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2, + ], + }, + ], +} +`; diff --git a/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-type-params.ts b/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-type-params.ts new file mode 100644 index 00000000000..ce2c80bdced --- /dev/null +++ b/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-type-params.ts @@ -0,0 +1,2 @@ +type Param = string; +type T = import('').foo; diff --git a/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-type-params.ts.shot b/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-type-params.ts.shot new file mode 100644 index 00000000000..4a48b256ff9 --- /dev/null +++ b/packages/scope-manager/tests/fixtures/type-declaration/import-type-with-type-params.ts.shot @@ -0,0 +1,63 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`type-declaration import-type-with-type-params 1`] = ` +ScopeManager { + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2 { + defs: Array [ + TypeDefinition$1 { + name: Identifier<"Param">, + node: TSTypeAliasDeclaration$1, + }, + ], + name: "Param", + references: Array [ + Reference$1 { + identifier: Identifier<"Param">, + isRead: true, + isTypeReference: true, + isValueReference: false, + isWrite: false, + resolved: Variable$2, + }, + ], + isValueVariable: false, + isTypeVariable: true, + }, + Variable$3 { + defs: Array [ + TypeDefinition$2 { + name: Identifier<"T">, + node: TSTypeAliasDeclaration$2, + }, + ], + name: "T", + references: Array [], + isValueVariable: false, + isTypeVariable: true, + }, + ], + scopes: Array [ + GlobalScope$1 { + block: Program$3, + isStrict: false, + references: Array [ + Reference$1, + ], + set: Map { + "const" => ImplicitGlobalConstTypeVariable, + "Param" => Variable$2, + "T" => Variable$3, + }, + type: "global", + upper: null, + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2, + Variable$3, + ], + }, + ], +} +`; diff --git a/packages/scope-manager/tests/fixtures/type-declaration/import-type.ts b/packages/scope-manager/tests/fixtures/type-declaration/import-type.ts new file mode 100644 index 00000000000..888f91b399a --- /dev/null +++ b/packages/scope-manager/tests/fixtures/type-declaration/import-type.ts @@ -0,0 +1 @@ +type T = import(''); diff --git a/packages/scope-manager/tests/fixtures/type-declaration/import-type.ts.shot b/packages/scope-manager/tests/fixtures/type-declaration/import-type.ts.shot new file mode 100644 index 00000000000..af47658faac --- /dev/null +++ b/packages/scope-manager/tests/fixtures/type-declaration/import-type.ts.shot @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`type-declaration import-type 1`] = ` +ScopeManager { + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2 { + defs: Array [ + TypeDefinition$1 { + name: Identifier<"T">, + node: TSTypeAliasDeclaration$1, + }, + ], + name: "T", + references: Array [], + isValueVariable: false, + isTypeVariable: true, + }, + ], + scopes: Array [ + GlobalScope$1 { + block: Program$2, + isStrict: false, + references: Array [], + set: Map { + "const" => ImplicitGlobalConstTypeVariable, + "T" => Variable$2, + }, + type: "global", + upper: null, + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2, + ], + }, + ], +} +`;