From 22e9ae59c9f0becdfe44cdcfb01a2b631daaee51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huy=20Dang=20L=C3=AA-Ng=C3=B4?= Date: Mon, 29 Jul 2019 13:34:56 -0700 Subject: [PATCH] fix(eslint-plugin): [no-explicit-any] Fix ignoreRestArgs for interfaces (#777) --- .../docs/rules/no-explicit-any.md | 30 +++++++ .../src/rules/no-explicit-any.ts | 4 +- .../tests/rules/no-explicit-any.test.ts | 81 +++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/no-explicit-any.md b/packages/eslint-plugin/docs/rules/no-explicit-any.md index ccec9e95231..861eb0566e2 100644 --- a/packages/eslint-plugin/docs/rules/no-explicit-any.md +++ b/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -128,6 +128,21 @@ const baz1 = function (...args: any[]) {} const baz2 = function (...args: readonly any[]) {} const baz3 = function (...args: Array) {} const baz4 = function (...args: ReadonlyArray) {} + +interface Qux1 { (...args: any[]): void; } +interface Qux2 { (...args: readonly any[]): void; } +interface Qux3 { (...args: Array): void; } +interface Qux4 { (...args: ReadonlyArray): void; } + +function quux1(fn: (...args: any[]) => void): void {} +function quux2(fn: (...args: readonly any[]) => void): void {} +function quux3(fn: (...args: Array) => void): void {} +function quux4(fn: (...args: ReadonlyArray) => void): void {} + +function quuz1(): ((...args: any[]) => void) {} +function quuz2(): ((...args: readonly any[]) => void) {} +function quuz3(): ((...args: Array) => void) {} +function quuz4(): ((...args: ReadonlyArray) => void) {} ``` Examples of **correct** code for the `{ "ignoreRestArgs": true }` option: @@ -149,6 +164,21 @@ const baz1 = function (...args: any[]) {} const baz2 = function (...args: readonly any[]) {} const baz3 = function (...args: Array) {} const baz4 = function (...args: ReadonlyArray) {} + +interface Qux1 { (...args: any[]): void; } +interface Qux2 { (...args: readonly any[]): void; } +interface Qux3 { (...args: Array): void; } +interface Qux4 { (...args: ReadonlyArray): void; } + +function quux1(fn: (...args: any[]) => void): void {} +function quux2(fn: (...args: readonly any[]) => void): void {} +function quux3(fn: (...args: Array) => void): void {} +function quux4(fn: (...args: ReadonlyArray) => void): void {} + +function quuz1(): ((...args: any[]) => void) {} +function quuz2(): ((...args: readonly any[]) => void) {} +function quuz3(): ((...args: Array) => void) {} +function quuz4(): ((...args: ReadonlyArray) => void) {} ``` ## When Not To Use It diff --git a/packages/eslint-plugin/src/rules/no-explicit-any.ts b/packages/eslint-plugin/src/rules/no-explicit-any.ts index a84327a0d55..43f81b8607e 100644 --- a/packages/eslint-plugin/src/rules/no-explicit-any.ts +++ b/packages/eslint-plugin/src/rules/no-explicit-any.ts @@ -51,7 +51,7 @@ export default util.createRule({ /** * Checks if the node is an arrow function, function declaration or function expression * @param node the node to be validated. - * @returns true if the node is an arrow function, function declaration or function expression + * @returns true if the node is an arrow function, function declaration, function expression, function type, or call signature * @private */ function isNodeValidFunction(node: TSESTree.Node): boolean { @@ -59,6 +59,8 @@ export default util.createRule({ AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.FunctionExpression, + AST_NODE_TYPES.TSFunctionType, + AST_NODE_TYPES.TSCallSignatureDeclaration, ].includes(node.type); } diff --git a/packages/eslint-plugin/tests/rules/no-explicit-any.test.ts b/packages/eslint-plugin/tests/rules/no-explicit-any.test.ts index b27cc8111bc..c5624ba0635 100644 --- a/packages/eslint-plugin/tests/rules/no-explicit-any.test.ts +++ b/packages/eslint-plugin/tests/rules/no-explicit-any.test.ts @@ -189,6 +189,54 @@ type obj = { code: `const baz4 = (...args: ReadonlyArray) => {}`, options: [{ ignoreRestArgs: true }], }, + { + code: `interface Qux1 { (...args: any[]): void; }`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `interface Qux2 { (...args: readonly any[]): void; }`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `interface Qux3 { (...args: Array): void; }`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `interface Qux4 { (...args: ReadonlyArray): void; }`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `function quux1(fn: (...args: any[]) => void): void {}`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `function quux2(fn: (...args: readonly any[]) => void): void {}`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `function quux3(fn: (...args: Array) => void): void {}`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `function quux4(fn: (...args: ReadonlyArray) => void): void {}`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `function quuz1(): ((...args: any[]) => void) {}`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `function quuz2(): ((...args: readonly any[]) => void) {}`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `function quuz3(): ((...args: Array) => void) {}`, + options: [{ ignoreRestArgs: true }], + }, + { + code: `function quuz4(): ((...args: ReadonlyArray) => void) {}`, + options: [{ ignoreRestArgs: true }], + }, ], invalid: ([ { @@ -787,6 +835,39 @@ type obj = { }, ], }, + { + code: `interface Qux5 { (...args: any): void; }`, + options: [{ ignoreRestArgs: true }], + errors: [ + { + messageId: 'unexpectedAny', + line: 1, + column: 28, + }, + ], + }, + { + code: `function quux5(fn: (...args: any) => void): void {}`, + options: [{ ignoreRestArgs: true }], + errors: [ + { + messageId: 'unexpectedAny', + line: 1, + column: 30, + }, + ], + }, + { + code: `function quuz5(): ((...args: any) => void) {}`, + options: [{ ignoreRestArgs: true }], + errors: [ + { + messageId: 'unexpectedAny', + line: 1, + column: 30, + }, + ], + }, ] as InvalidTestCase[]).reduce((acc, testCase) => { acc.push(testCase); const options = testCase.options || [];