From 62c4fda03921ab67b493c3a688cf82d480bcd831 Mon Sep 17 00:00:00 2001 From: Tadhg McDonald-Jensen Date: Thu, 3 Sep 2020 18:29:21 -0400 Subject: [PATCH 1/4] fix: implemented allowThisAsVoid option --- .../docs/rules/no-invalid-void-type.md | 19 +++++++ .../src/rules/no-invalid-void-type.ts | 45 +++++++++++++--- .../tests/rules/no-invalid-void-type.test.ts | 53 +++++++++++++++++++ 3 files changed, 109 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-invalid-void-type.md b/packages/eslint-plugin/docs/rules/no-invalid-void-type.md index f1607478a0d..840e6a24561 100644 --- a/packages/eslint-plugin/docs/rules/no-invalid-void-type.md +++ b/packages/eslint-plugin/docs/rules/no-invalid-void-type.md @@ -54,10 +54,12 @@ type stillVoid = void | never; ```ts interface Options { allowInGenericTypeArguments?: boolean | string[]; + allowAsThisParameter?: boolean; } const defaultOptions: Options = { allowInGenericTypeArguments: true, + allowAsThisParameter: false, }; ``` @@ -97,6 +99,23 @@ type AllowedVoid = Ex.Mx.Tx; type AllowedVoidUnion = void | Ex.Mx.Tx; ``` +#### `allowAsThisParameter` + +This option allows specifying a `this` parameter of a function to be `void` when set to `true`. +TypeScript [recommends using this pattern](https://www.typescriptlang.org/docs/handbook/functions.html#this-parameters-in-callbacks) to explicitly label function types that do not use a this argument. + +This option is `false` by default. + +The following patterns are considered warnings with `{ allowAsThisParameter: false }` but valid with `{ allowAsThisParameter: true }`: + +```ts +function doThing(this: void) {} +class Example { + static helper(this: void) {} + callback(this: void) {} +} +``` + ## When Not To Use It If you don't care about if `void` is used with other types, diff --git a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts index b78107bac65..6a6afd015ec 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts @@ -5,13 +5,16 @@ import { import * as util from '../util'; interface Options { - allowInGenericTypeArguments: boolean | string[]; + allowInGenericTypeArguments?: boolean | string[]; + allowAsThisParameter?: boolean; } type MessageIds = | 'invalidVoidForGeneric' | 'invalidVoidNotReturnOrGeneric' - | 'invalidVoidNotReturn'; + | 'invalidVoidNotReturn' + | 'invalidVoidNotReturnOrThisParam' + | 'invalidVoidNotReturnOrThisParamOrGeneric'; export default util.createRule<[Options], MessageIds>({ name: 'no-invalid-void-type', @@ -29,6 +32,10 @@ export default util.createRule<[Options], MessageIds>({ invalidVoidNotReturnOrGeneric: 'void is only valid as a return type or generic type variable', invalidVoidNotReturn: 'void is only valid as a return type', + invalidVoidNotReturnOrThisParam: + 'void is only valid as return type or type of this parameter', + invalidVoidNotReturnOrThisParamOrGeneric: + 'void is only valid as a return type or generic type variable or in this parameter', }, schema: [ { @@ -44,13 +51,18 @@ export default util.createRule<[Options], MessageIds>({ }, ], }, + allowAsThisParameter: { + type: 'boolean', + }, }, additionalProperties: false, }, ], }, - defaultOptions: [{ allowInGenericTypeArguments: true }], - create(context, [{ allowInGenericTypeArguments }]) { + defaultOptions: [ + { allowInGenericTypeArguments: true, allowAsThisParameter: false }, + ], + create(context, [{ allowInGenericTypeArguments, allowAsThisParameter }]) { const validParents: AST_NODE_TYPES[] = [ AST_NODE_TYPES.TSTypeAnnotation, // ]; @@ -110,7 +122,9 @@ export default util.createRule<[Options], MessageIds>({ if (!allowInGenericTypeArguments) { context.report({ - messageId: 'invalidVoidNotReturn', + messageId: allowAsThisParameter + ? 'invalidVoidNotReturnOrThisParam' + : 'invalidVoidNotReturn', node, }); } @@ -159,6 +173,16 @@ export default util.createRule<[Options], MessageIds>({ return; } + // this parameter is ok to be void. + if ( + allowAsThisParameter && + node.parent.type === AST_NODE_TYPES.TSTypeAnnotation && + node.parent.parent.type === AST_NODE_TYPES.Identifier && + node.parent.parent.name === 'this' + ) { + return; + } + // default cases if ( validParents.includes(node.parent.type) && @@ -168,9 +192,14 @@ export default util.createRule<[Options], MessageIds>({ } context.report({ - messageId: allowInGenericTypeArguments - ? 'invalidVoidNotReturnOrGeneric' - : 'invalidVoidNotReturn', + messageId: + allowInGenericTypeArguments && allowAsThisParameter + ? 'invalidVoidNotReturnOrThisParamOrGeneric' + : allowInGenericTypeArguments + ? 'invalidVoidNotReturnOrGeneric' + : allowAsThisParameter + ? 'invalidVoidNotReturnOrThisParam' + : 'invalidVoidNotReturn', node, }); }, diff --git a/packages/eslint-plugin/tests/rules/no-invalid-void-type.test.ts b/packages/eslint-plugin/tests/rules/no-invalid-void-type.test.ts index 31771c561c0..56df4f47ab6 100644 --- a/packages/eslint-plugin/tests/rules/no-invalid-void-type.test.ts +++ b/packages/eslint-plugin/tests/rules/no-invalid-void-type.test.ts @@ -538,3 +538,56 @@ async function foo(bar: () => void | Promise) { }, ], }); + +ruleTester.run('allowAsThisParameter: true', rule, { + valid: [ + { + code: 'function f(this: void) {}', + options: [{ allowAsThisParameter: true }], + }, + { + code: ` +class Test { + public static helper(this: void) {} + method(this: void) {} +} + `, + options: [{ allowAsThisParameter: true }], + }, + ], + invalid: [ + { + code: 'type alias = void;', + options: [ + { allowAsThisParameter: true, allowInGenericTypeArguments: true }, + ], + errors: [ + { + messageId: 'invalidVoidNotReturnOrThisParamOrGeneric', + }, + ], + }, + { + code: 'type alias = void;', + options: [ + { allowAsThisParameter: true, allowInGenericTypeArguments: false }, + ], + errors: [ + { + messageId: 'invalidVoidNotReturnOrThisParam', + }, + ], + }, + { + code: 'type alias = Array;', + options: [ + { allowAsThisParameter: true, allowInGenericTypeArguments: false }, + ], + errors: [ + { + messageId: 'invalidVoidNotReturnOrThisParam', + }, + ], + }, + ], +}); From a13794f13296b2f10790043f2634d031d1e43250 Mon Sep 17 00:00:00 2001 From: Tadhg McDonald-Jensen Date: Thu, 24 Sep 2020 10:52:34 -0400 Subject: [PATCH 2/4] Update packages/eslint-plugin/src/rules/no-invalid-void-type.ts --- packages/eslint-plugin/src/rules/no-invalid-void-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts index 6a6afd015ec..056527a66e7 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts @@ -33,7 +33,7 @@ export default util.createRule<[Options], MessageIds>({ 'void is only valid as a return type or generic type variable', invalidVoidNotReturn: 'void is only valid as a return type', invalidVoidNotReturnOrThisParam: - 'void is only valid as return type or type of this parameter', + 'void is only valid as return type or type of `this` parameter', invalidVoidNotReturnOrThisParamOrGeneric: 'void is only valid as a return type or generic type variable or in this parameter', }, From 8dde9b4421b6cfc0ff6981be0a35017b97e625ed Mon Sep 17 00:00:00 2001 From: Tadhg McDonald-Jensen Date: Thu, 24 Sep 2020 10:52:42 -0400 Subject: [PATCH 3/4] Update packages/eslint-plugin/src/rules/no-invalid-void-type.ts --- packages/eslint-plugin/src/rules/no-invalid-void-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts index 056527a66e7..0dff489e585 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts @@ -35,7 +35,7 @@ export default util.createRule<[Options], MessageIds>({ invalidVoidNotReturnOrThisParam: 'void is only valid as return type or type of `this` parameter', invalidVoidNotReturnOrThisParamOrGeneric: - 'void is only valid as a return type or generic type variable or in this parameter', + 'void is only valid as a return type or generic type variable or the type of a `this` parameter', }, schema: [ { From 81e51f577d3a2d3ae85e9fc12b510ba1dc7be824 Mon Sep 17 00:00:00 2001 From: Tadhg McDonald-Jensen Date: Mon, 28 Sep 2020 08:36:58 -0400 Subject: [PATCH 4/4] Update packages/eslint-plugin/docs/rules/no-invalid-void-type.md incorperate review. --- packages/eslint-plugin/docs/rules/no-invalid-void-type.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/no-invalid-void-type.md b/packages/eslint-plugin/docs/rules/no-invalid-void-type.md index 840e6a24561..567d9c0bb33 100644 --- a/packages/eslint-plugin/docs/rules/no-invalid-void-type.md +++ b/packages/eslint-plugin/docs/rules/no-invalid-void-type.md @@ -102,7 +102,7 @@ type AllowedVoidUnion = void | Ex.Mx.Tx; #### `allowAsThisParameter` This option allows specifying a `this` parameter of a function to be `void` when set to `true`. -TypeScript [recommends using this pattern](https://www.typescriptlang.org/docs/handbook/functions.html#this-parameters-in-callbacks) to explicitly label function types that do not use a this argument. +This pattern can be useful to explicitly label function types that do not use a `this` argument. [See the TypeScript docs for more information](https://www.typescriptlang.org/docs/handbook/functions.html#this-parameters-in-callbacks). This option is `false` by default.