From fc0a55e8b78203972d01a7c9b79ed6b470c5c1a0 Mon Sep 17 00:00:00 2001 From: Alexander T Date: Sat, 29 Feb 2020 04:31:28 +0200 Subject: [PATCH] feat(eslint-plugin): [typedef] add variable-declaration-ignore-function (#1578) --- packages/eslint-plugin/docs/rules/typedef.md | 27 +++- packages/eslint-plugin/src/rules/typedef.ts | 17 ++- .../eslint-plugin/tests/rules/typedef.test.ts | 120 ++++++++++++++++++ 3 files changed, 162 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/typedef.md b/packages/eslint-plugin/docs/rules/typedef.md index 17a57412bc2..07f4bb1eb3a 100644 --- a/packages/eslint-plugin/docs/rules/typedef.md +++ b/packages/eslint-plugin/docs/rules/typedef.md @@ -37,7 +37,8 @@ This rule has an object option that may receive any of the following as booleans - `"objectDestructuring"` - `"parameter"`: `true` by default - `"propertyDeclaration"`: `true` by default -- `"variableDeclaration"` +- `"variableDeclaration"`, +- `"variableDeclarationIgnoreFunction"` For example, with the following configuration: @@ -254,6 +255,30 @@ let initialText: string = 'text'; let delayedText: string; ``` +### `variableDeclarationIgnoreFunction` + +Ignore variable declarations for non-arrow and arrow functions. + +Examples of **incorrect** code with `{ "variableDeclaration": true, "variableDeclarationIgnoreFunction": true }`: + +```ts +const text = 'text'; +``` + +Examples of **correct** code with `{ "variableDeclaration": true, "variableDeclarationIgnoreFunction": true }`: + +```ts +const a = (): void => {}; +const b = function (): void => {}; +const c: () => void = (): void => {}; + +class Foo { + a = (): void => {}; + b = function (): void => {}; + c = () => void = (): void => {}; +} +``` + ## When Not To Use It If you are using stricter TypeScript compiler options, particularly `--noImplicitAny` and/or `--strictPropertyInitialization`, you likely don't need this rule. diff --git a/packages/eslint-plugin/src/rules/typedef.ts b/packages/eslint-plugin/src/rules/typedef.ts index dd7bcc29c61..7e6f4f14965 100644 --- a/packages/eslint-plugin/src/rules/typedef.ts +++ b/packages/eslint-plugin/src/rules/typedef.ts @@ -12,6 +12,7 @@ const enum OptionKeys { Parameter = 'parameter', PropertyDeclaration = 'propertyDeclaration', VariableDeclaration = 'variableDeclaration', + VariableDeclarationIgnoreFunction = 'variableDeclarationIgnoreFunction', } type Options = { [k in OptionKeys]?: boolean }; @@ -41,6 +42,7 @@ export default util.createRule<[Options], MessageIds>({ [OptionKeys.Parameter]: { type: 'boolean' }, [OptionKeys.PropertyDeclaration]: { type: 'boolean' }, [OptionKeys.VariableDeclaration]: { type: 'boolean' }, + [OptionKeys.VariableDeclarationIgnoreFunction]: { type: 'boolean' }, }, }, ], @@ -125,6 +127,14 @@ export default util.createRule<[Options], MessageIds>({ } } + function isVariableDeclarationIgnoreFunction(node: TSESTree.Node): boolean { + return ( + !!options[OptionKeys.VariableDeclarationIgnoreFunction] && + (node.type === AST_NODE_TYPES.FunctionExpression || + node.type === AST_NODE_TYPES.ArrowFunctionExpression) + ); + } + return { ArrayPattern(node): void { if ( @@ -141,6 +151,10 @@ export default util.createRule<[Options], MessageIds>({ } }, ClassProperty(node): void { + if (node.value && isVariableDeclarationIgnoreFunction(node.value)) { + return; + } + if ( options[OptionKeys.MemberVariableDeclaration] && !node.typeAnnotation @@ -188,7 +202,8 @@ export default util.createRule<[Options], MessageIds>({ (node.id.type === AST_NODE_TYPES.ArrayPattern && !options[OptionKeys.ArrayDestructuring]) || (node.id.type === AST_NODE_TYPES.ObjectPattern && - !options[OptionKeys.ObjectDestructuring]) + !options[OptionKeys.ObjectDestructuring]) || + (node.init && isVariableDeclarationIgnoreFunction(node.init)) ) { return; } diff --git a/packages/eslint-plugin/tests/rules/typedef.test.ts b/packages/eslint-plugin/tests/rules/typedef.test.ts index 679ed1a8a51..bbb1a49c018 100644 --- a/packages/eslint-plugin/tests/rules/typedef.test.ts +++ b/packages/eslint-plugin/tests/rules/typedef.test.ts @@ -302,6 +302,57 @@ ruleTester.run('typedef', rule, { }, ], }, + // variable declaration ignore function + { + code: `const foo = function(): void {};`, + options: [ + { + variableDeclaration: true, + variableDeclarationIgnoreFunction: true, + }, + ], + }, + { + code: `const foo = (): void => {};`, + options: [ + { + variableDeclaration: true, + variableDeclarationIgnoreFunction: true, + }, + ], + }, + { + code: `const foo: () => void = (): void => {};`, + options: [ + { + variableDeclaration: true, + variableDeclarationIgnoreFunction: true, + }, + ], + }, + { + code: `const foo: () => void = function (): void {};`, + options: [ + { + variableDeclaration: true, + variableDeclarationIgnoreFunction: true, + }, + ], + }, + { + code: ` +class Foo { + a = (): void => {}; + b = function (): void {}; +} + `, + options: [ + { + variableDeclaration: true, + variableDeclarationIgnoreFunction: true, + }, + ], + }, ], invalid: [ // Array destructuring @@ -652,5 +703,74 @@ ruleTester.run('typedef', rule, { }, ], }, + { + code: `const foo = 'foo'`, + errors: [ + { + messageId: 'expectedTypedefNamed', + data: { name: 'foo' }, + }, + ], + options: [ + { + variableDeclaration: true, + variableDeclarationIgnoreFunction: true, + }, + ], + }, + { + code: `const foo = function(): void {};`, + errors: [ + { + messageId: 'expectedTypedefNamed', + data: { name: 'foo' }, + }, + ], + options: [ + { + variableDeclaration: true, + variableDeclarationIgnoreFunction: false, + }, + ], + }, + { + code: `const foo = (): void => {};`, + errors: [ + { + messageId: 'expectedTypedefNamed', + data: { name: 'foo' }, + }, + ], + options: [ + { + variableDeclaration: true, + variableDeclarationIgnoreFunction: false, + }, + ], + }, + { + code: ` +class Foo { + a = (): void => {}; + b = function (): void {}; +} + `, + errors: [ + { + messageId: 'expectedTypedefNamed', + data: { name: 'a' }, + }, + { + messageId: 'expectedTypedefNamed', + data: { name: 'b' }, + }, + ], + options: [ + { + variableDeclaration: true, + variableDeclarationIgnoreFunction: false, + }, + ], + }, ], });