From 243180371e47cba01ab31510a6820786beeefaff Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 17:54:05 +0200 Subject: [PATCH 01/20] initial implementation --- .../src/rules/no-misused-promises.ts | 66 ++++++++++++++++--- packages/eslint-plugin/src/util/misc.ts | 4 +- .../tests/rules/no-misused-promises.test.ts | 55 ++++++++++++++++ 3 files changed, 114 insertions(+), 11 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index c80b253c650e..d99d2ee2aefe 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -7,6 +7,7 @@ import * as ts from 'typescript'; import { createRule, getParserServices, + getStaticMemberAccessValue, isArrayMethodCallWithPredicate, isFunction, isRestParameterDeclaration, @@ -568,11 +569,26 @@ export default createRule({ continue; } + if ( + node.type !== AST_NODE_TYPES.MethodDefinition && + node.type !== AST_NODE_TYPES.TSAbstractMethodDefinition && + node.type !== AST_NODE_TYPES.TSMethodSignature && + node.type !== AST_NODE_TYPES.TSPropertySignature + ) { + continue; + } + + const staticAccessValue = getStaticMemberAccessValue(node, context); + + if (!staticAccessValue) { + continue; + } + for (const heritageType of heritageTypes) { checkHeritageTypeForMemberReturningVoid( nodeMember, heritageType, - memberName, + staticAccessValue, ); } } @@ -588,9 +604,13 @@ export default createRule({ function checkHeritageTypeForMemberReturningVoid( nodeMember: ts.Node, heritageType: ts.Type, - memberName: string, + staticAccessValue: string | symbol, ): void { - const heritageMember = getMemberIfExists(heritageType, memberName); + const heritageMember = getMemberIfExists( + heritageType, + staticAccessValue, + checker, + ); if (heritageMember === undefined) { return; } @@ -944,18 +964,44 @@ function getHeritageTypes( .map(typeExpression => checker.getTypeAtLocation(typeExpression)); } +function getWellKnownStringOfSymbol(symbol: symbol): string | null { + switch (symbol) { + case Symbol.iterator: + return 'iterator'; + case Symbol.asyncIterator: + return 'asyncIterator'; + } + + return null; +} + /** - * @returns The member with the given name in `type`, if it exists. + * @returns The member with the given name or known-symbol in `type`, if it exists. */ function getMemberIfExists( type: ts.Type, - memberName: string, + staticAccessValue: string | symbol, + checker: ts.TypeChecker, ): ts.Symbol | undefined { - const escapedMemberName = ts.escapeLeadingUnderscores(memberName); - const symbolMemberMatch = type.getSymbol()?.members?.get(escapedMemberName); - return ( - symbolMemberMatch ?? tsutils.getPropertyOfType(type, escapedMemberName) - ); + if (typeof staticAccessValue === 'string') { + const escapedMemberName = ts.escapeLeadingUnderscores(staticAccessValue); + const symbolMemberMatch = type.getSymbol()?.members?.get(escapedMemberName); + return ( + symbolMemberMatch ?? tsutils.getPropertyOfType(type, escapedMemberName) + ); + } + + const wellKnownSymbolName = getWellKnownStringOfSymbol(staticAccessValue); + + if (wellKnownSymbolName) { + return tsutils.getWellKnownSymbolPropertyOfType( + type, + wellKnownSymbolName, + checker, + ); + } + + return undefined; } function isStaticMember(node: TSESTree.Node): boolean { diff --git a/packages/eslint-plugin/src/util/misc.ts b/packages/eslint-plugin/src/util/misc.ts index 4e65d2287133..38eb0459bb7b 100644 --- a/packages/eslint-plugin/src/util/misc.ts +++ b/packages/eslint-plugin/src/util/misc.ts @@ -239,7 +239,9 @@ type NodeWithKey = | TSESTree.Property | TSESTree.PropertyDefinition | TSESTree.TSAbstractMethodDefinition - | TSESTree.TSAbstractPropertyDefinition; + | TSESTree.TSAbstractPropertyDefinition + | TSESTree.TSMethodSignature + | TSESTree.TSPropertySignature; /** * Gets a member being accessed or declared if its value can be determined statically, and diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index ed685906ee99..c7336d4c113d 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -2429,5 +2429,60 @@ arrayFn<() => void>( }, ], }, + + { + code: ` +const staticSymbol = Symbol.for('static symbol'); + +interface Interface { + identifier: () => void; + 1: () => void; + 2: () => void; + stringLiteral: () => void; + computedStringLiteral: () => void; + // well known symbol + [Symbol.iterator]: () => void; + + // less sure if this one is possible to lint for + [staticSymbol]: () => void; +} + +class Clazz implements Interface { + async identifier() {} + async 1() {} + async [2]() {} + async stringLiteral() {} + async ['computedStringLiteral']() {} + async [Symbol.iterator]() {} + async [staticSymbol]() {} +} + `, + errors: [ + { + line: 18, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 19, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 20, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 21, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 22, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 23, + messageId: 'voidReturnInheritedMethod', + }, + ], + }, ], }); From 35bd930b8e07b0c5671f2233b938ebc988d2e6e6 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 18:03:33 +0200 Subject: [PATCH 02/20] test asyncIterator symbol --- .../tests/rules/no-misused-promises.test.ts | 78 +++++++++++++++++-- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index c7336d4c113d..651063765df2 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -1042,6 +1042,68 @@ interface MyInterface extends MyCall, MyIndex, MyConstruct, MyMethods { `, options: [{ checksVoidReturn: { inheritedMethods: true } }], }, + { + code: ` +const staticSymbol = Symbol.for('static symbol'); + +interface Interface { + identifier: () => void; + 1: () => void; + 2: () => void; + stringLiteral: () => void; + computedStringLiteral: () => void; + // well known symbols + [Symbol.iterator]: () => void; + [Symbol.asyncIterator]: () => void; + + // less sure if this one is possible to lint for + [staticSymbol]: () => void; +} + +class Clazz implements Interface { + identifier(): void {} + 1(): void {} + [2](): void {} + stringLiteral(): void {} + ['computedStringLiteral'](): void {} + [Symbol.iterator](): void {} + [Symbol.asyncIterator](): void {} + [staticSymbol](): void {} +} + `, + options: [{ checksVoidReturn: { inheritedMethods: true } }], + }, + { + code: ` +const staticSymbol = Symbol.for('static symbol'); + +interface Interface { + identifier: () => void; + 1: () => void; + 2: () => void; + stringLiteral: () => void; + computedStringLiteral: () => void; + // well known symbols + [Symbol.iterator]: () => void; + [Symbol.asyncIterator]: () => void; + + // less sure if this one is possible to lint for + [staticSymbol]: () => void; +} + +class Clazz implements Interface { + async identifier() {} + async 1() {} + async [2]() {} + async stringLiteral() {} + async ['computedStringLiteral']() {} + async [Symbol.iterator]() {} + async [Symbol.asyncIterator]() {} + async [staticSymbol]() {} +} + `, + options: [{ checksVoidReturn: { inheritedMethods: false } }], + }, "const notAFn1: string = '';", 'const notAFn2: number = 1;', 'const notAFn3: boolean = true;', @@ -2440,8 +2502,9 @@ interface Interface { 2: () => void; stringLiteral: () => void; computedStringLiteral: () => void; - // well known symbol + // well known symbols [Symbol.iterator]: () => void; + [Symbol.asyncIterator]: () => void; // less sure if this one is possible to lint for [staticSymbol]: () => void; @@ -2454,14 +2517,11 @@ class Clazz implements Interface { async stringLiteral() {} async ['computedStringLiteral']() {} async [Symbol.iterator]() {} + async [Symbol.asyncIterator]() {} async [staticSymbol]() {} } `, errors: [ - { - line: 18, - messageId: 'voidReturnInheritedMethod', - }, { line: 19, messageId: 'voidReturnInheritedMethod', @@ -2482,6 +2542,14 @@ class Clazz implements Interface { line: 23, messageId: 'voidReturnInheritedMethod', }, + { + line: 24, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 25, + messageId: 'voidReturnInheritedMethod', + }, ], }, ], From 61f8e0c6e3ece3ea26a69689eb917d61011b3a5d Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 18:59:24 +0200 Subject: [PATCH 03/20] support properties --- .../eslint-plugin/src/rules/no-misused-promises.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index d99d2ee2aefe..0e5a0120bb52 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -455,9 +455,6 @@ export default createRule({ }); } } else if (ts.isMethodDeclaration(tsNode)) { - if (ts.isComputedPropertyName(tsNode.name)) { - return; - } const obj = tsNode.parent; // Below condition isn't satisfied unless something goes wrong, @@ -477,9 +474,14 @@ export default createRule({ if (objType === undefined) { return; } - const propertySymbol = checker.getPropertyOfType( + const staticAccessValue = getStaticMemberAccessValue(node, context); + if (!staticAccessValue) { + return; + } + const propertySymbol = getMemberIfExists( objType, - tsNode.name.text, + staticAccessValue, + checker, ); if (propertySymbol === undefined) { return; From f4107ffa6ca7f4d1ecfadbd25fb18aab2df3beaf Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 19:25:13 +0200 Subject: [PATCH 04/20] update tests --- .../tests/rules/no-misused-promises.test.ts | 280 +++++++++--------- 1 file changed, 141 insertions(+), 139 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index 651063765df2..011e33e6633f 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -1,4 +1,4 @@ -import { RuleTester } from '@typescript-eslint/rule-tester'; +import { noFormat, RuleTester } from '@typescript-eslint/rule-tester'; import rule from '../../src/rules/no-misused-promises'; import { getFixturesRootDir } from '../RuleTester'; @@ -1042,68 +1042,6 @@ interface MyInterface extends MyCall, MyIndex, MyConstruct, MyMethods { `, options: [{ checksVoidReturn: { inheritedMethods: true } }], }, - { - code: ` -const staticSymbol = Symbol.for('static symbol'); - -interface Interface { - identifier: () => void; - 1: () => void; - 2: () => void; - stringLiteral: () => void; - computedStringLiteral: () => void; - // well known symbols - [Symbol.iterator]: () => void; - [Symbol.asyncIterator]: () => void; - - // less sure if this one is possible to lint for - [staticSymbol]: () => void; -} - -class Clazz implements Interface { - identifier(): void {} - 1(): void {} - [2](): void {} - stringLiteral(): void {} - ['computedStringLiteral'](): void {} - [Symbol.iterator](): void {} - [Symbol.asyncIterator](): void {} - [staticSymbol](): void {} -} - `, - options: [{ checksVoidReturn: { inheritedMethods: true } }], - }, - { - code: ` -const staticSymbol = Symbol.for('static symbol'); - -interface Interface { - identifier: () => void; - 1: () => void; - 2: () => void; - stringLiteral: () => void; - computedStringLiteral: () => void; - // well known symbols - [Symbol.iterator]: () => void; - [Symbol.asyncIterator]: () => void; - - // less sure if this one is possible to lint for - [staticSymbol]: () => void; -} - -class Clazz implements Interface { - async identifier() {} - async 1() {} - async [2]() {} - async stringLiteral() {} - async ['computedStringLiteral']() {} - async [Symbol.iterator]() {} - async [Symbol.asyncIterator]() {} - async [staticSymbol]() {} -} - `, - options: [{ checksVoidReturn: { inheritedMethods: false } }], - }, "const notAFn1: string = '';", 'const notAFn2: number = 1;', 'const notAFn3: boolean = true;', @@ -1445,43 +1383,126 @@ const g = async () => 1, { code: ` const obj: { - f?: () => void; + identifier?: () => void; + 1?: () => void; + computedStringLiteral?: () => void; + [Symbol.iterator]?: () => void; } = {}; -obj.f = async () => { +obj.identifier = async () => { + return 0; +}; +obj[1] = async () => { + return 0; +}; +obj['computedStringLiteral'] = async () => { + return 0; +}; +obj[Symbol.iterator] = async () => { return 0; }; `, errors: [ { - line: 5, + line: 8, + messageId: 'voidReturnVariable', + }, + { + line: 11, + messageId: 'voidReturnVariable', + }, + { + line: 14, + messageId: 'voidReturnVariable', + }, + { + line: 17, messageId: 'voidReturnVariable', }, ], }, { - code: ` -type O = { f: () => void }; + code: noFormat` +type O = { + identifier: () => void; + 1: () => void; + stringLiteral: () => void; + computedStringLiteral: () => void; + [Symbol.iterator]: () => void; +}; const obj: O = { - f: async () => 'foo', + identifier: async () => 'foo', + [1]: async () => 'foo', + 'stringLiteral': async () => 'foo', + ['computedStringLiteral']: async () => 'foo', + [Symbol.iterator]: async () => 'foo', }; `, errors: [ { - line: 4, + line: 10, + messageId: 'voidReturnProperty', + }, + { + line: 11, + messageId: 'voidReturnProperty', + }, + { + line: 12, + messageId: 'voidReturnProperty', + }, + { + line: 13, + messageId: 'voidReturnProperty', + }, + { + line: 14, messageId: 'voidReturnProperty', }, ], }, { - code: ` -type O = { f: () => void }; + code: noFormat` +type O = { + identifier: () => void; + 1: () => void; + 2: () => void; + stringLiteral: () => void; + computedStringLiteral: () => void; + [Symbol.iterator]: () => void; +}; const obj: O = { - f: async () => 'foo', + identifier: async () => 'foo', + 1: async () => 'foo', + [2]: async () => 'foo', + 'stringLiteral': async () => 'foo', + ['computedStringLiteral']: async () => 'foo', + [Symbol.iterator]: async () => 'foo', + [staticSymbol]: async () => 'foo', }; `, errors: [ { - line: 4, + line: 11, + messageId: 'voidReturnProperty', + }, + { + line: 12, + messageId: 'voidReturnProperty', + }, + { + line: 13, + messageId: 'voidReturnProperty', + }, + { + line: 14, + messageId: 'voidReturnProperty', + }, + { + line: 15, + messageId: 'voidReturnProperty', + }, + { + line: 16, messageId: 'voidReturnProperty', }, ], @@ -1503,17 +1524,59 @@ const obj: O = { ], }, { - code: ` -type O = { f: () => void }; + code: noFormat` +type O = { + identifier: () => void; + 1: () => void; + 2: () => void; + stringLiteral: () => void; + computedStringLiteral: () => void; + [Symbol.iterator]: () => void; +}; const obj: O = { - async f() { + async identifier() { + return 0; + }, + async 1() { + return 0; + }, + async [2]() { + return 0; + }, + async 'stringLiteral'() { + return 0; + }, + async ['computedStringLiteral']() { + return 0; + }, + async [Symbol.iterator]() { return 0; }, }; `, errors: [ { - line: 4, + line: 11, + messageId: 'voidReturnProperty', + }, + { + line: 14, + messageId: 'voidReturnProperty', + }, + { + line: 17, + messageId: 'voidReturnProperty', + }, + { + line: 20, + messageId: 'voidReturnProperty', + }, + { + line: 23, + messageId: 'voidReturnProperty', + }, + { + line: 26, messageId: 'voidReturnProperty', }, ], @@ -2491,66 +2554,5 @@ arrayFn<() => void>( }, ], }, - - { - code: ` -const staticSymbol = Symbol.for('static symbol'); - -interface Interface { - identifier: () => void; - 1: () => void; - 2: () => void; - stringLiteral: () => void; - computedStringLiteral: () => void; - // well known symbols - [Symbol.iterator]: () => void; - [Symbol.asyncIterator]: () => void; - - // less sure if this one is possible to lint for - [staticSymbol]: () => void; -} - -class Clazz implements Interface { - async identifier() {} - async 1() {} - async [2]() {} - async stringLiteral() {} - async ['computedStringLiteral']() {} - async [Symbol.iterator]() {} - async [Symbol.asyncIterator]() {} - async [staticSymbol]() {} -} - `, - errors: [ - { - line: 19, - messageId: 'voidReturnInheritedMethod', - }, - { - line: 20, - messageId: 'voidReturnInheritedMethod', - }, - { - line: 21, - messageId: 'voidReturnInheritedMethod', - }, - { - line: 22, - messageId: 'voidReturnInheritedMethod', - }, - { - line: 23, - messageId: 'voidReturnInheritedMethod', - }, - { - line: 24, - messageId: 'voidReturnInheritedMethod', - }, - { - line: 25, - messageId: 'voidReturnInheritedMethod', - }, - ], - }, ], }); From 2c4ff28fbf60cbb21af072be1f27615436312a0c Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 21:22:02 +0200 Subject: [PATCH 05/20] update additional tests --- .../tests/rules/no-misused-promises.test.ts | 461 +++++++++++++++++- 1 file changed, 440 insertions(+), 21 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index 011e33e6633f..f32400bbab48 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -1477,7 +1477,6 @@ const obj: O = { 'stringLiteral': async () => 'foo', ['computedStringLiteral']: async () => 'foo', [Symbol.iterator]: async () => 'foo', - [staticSymbol]: async () => 'foo', }; `, errors: [ @@ -1582,8 +1581,17 @@ const obj: O = { ], }, { - code: ` -type O = { f: () => void; g: () => void; h: () => void }; + code: noFormat` +type O = { + f: () => void; + g: () => void; + h: () => void; + 1: () => void; + 2: () => void; + stringLiteral: () => void; + computedStringLiteral: () => void; + [Symbol.iterator]: () => void; +}; function f(): O { const h = async () => 0; return { @@ -1592,20 +1600,55 @@ function f(): O { }, g: async () => 0, h, + async 1() { + return 123; + }, + async [2]() { + return 123; + }, + async 'stringLiteral'() { + return 123; + }, + async ['computedStringLiteral']() { + return 123; + }, + async [Symbol.iterator]() { + return 123; + }, }; } `, errors: [ { - line: 6, + line: 15, messageId: 'voidReturnProperty', }, { - line: 9, + line: 18, messageId: 'voidReturnProperty', }, { - line: 10, + line: 19, + messageId: 'voidReturnProperty', + }, + { + line: 20, + messageId: 'voidReturnProperty', + }, + { + line: 23, + messageId: 'voidReturnProperty', + }, + { + line: 26, + messageId: 'voidReturnProperty', + }, + { + line: 29, + messageId: 'voidReturnProperty', + }, + { + line: 32, messageId: 'voidReturnProperty', }, ], @@ -1973,43 +2016,143 @@ consume(...cbs); errors: [{ line: 4, messageId: 'voidReturnArgument' }], }, { - code: ` + code: noFormat` class MyClass { setThing(): void { return; } + 1(): void { + return; + } + 2(): void { + return; + } + stringLiteral(): void { + return; + } + computedStringLiteral(): void { + return; + } + [Symbol.iterator](): void { + return; + } } class MySubclassExtendsMyClass extends MyClass { async setThing(): Promise { await Promise.resolve(); } + async 1(): Promise { + await Promise.resolve(); + } + async [2](): Promise { + await Promise.resolve(); + } + async 'stringLiteral'(): Promise { + await Promise.resolve(); + } + async ['computedStringLiteral'](): Promise { + await Promise.resolve(); + } + async [Symbol.iterator](): Promise { + await Promise.resolve(); + } } `, errors: [ { data: { heritageTypeName: 'MyClass' }, - line: 9, + line: 24, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 27, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 30, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 33, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 36, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 39, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: ` + code: noFormat` class MyClass { setThing(): void { return; } + 1(): void { + return; + } + 2(): void { + return; + } + stringLiteral(): void { + return; + } + computedStringLiteral(): void { + return; + } + [Symbol.iterator](): void { + return; + } } abstract class MyAbstractClassExtendsMyClass extends MyClass { abstract setThing(): Promise; + abstract 1(): Promise; + abstract [2](): Promise; + abstract 'stringLiteral'(): Promise; + abstract ['computedStringLiteral'](): Promise; + abstract [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyClass' }, - line: 9, + line: 24, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 25, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 26, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 27, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 28, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 29, messageId: 'voidReturnInheritedMethod', }, ], @@ -2020,54 +2163,179 @@ class MyClass { setThing(): void { return; } + 1(): void { + return; + } + 2(): void { + return; + } + stringLiteral(): void { + return; + } + computedStringLiteral(): void { + return; + } + [Symbol.iterator](): void { + return; + } } interface MyInterfaceExtendsMyClass extends MyClass { setThing(): Promise; + 1(): Promise; + [2](): Promise; + 'stringLiteral'(): Promise; + ['computedStringLiteral'](): Promise; + [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyClass' }, - line: 9, + line: 24, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 25, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 26, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 27, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 28, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 29, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: ` + code: noFormat` abstract class MyAbstractClass { abstract setThing(): void; + abstract 1(): void; + abstract 2(): void; + abstract stringLiteral(): void; + abstract computedStringLiteral(): void; + abstract [Symbol.iterator](): void; } class MySubclassExtendsMyAbstractClass extends MyAbstractClass { async setThing(): Promise { await Promise.resolve(); } + async 1(): Promise { + await Promise.resolve(); + } + async [2](): Promise { + await Promise.resolve(); + } + async 'stringLiteral'(): Promise { + await Promise.resolve(); + } + async ['computedStringLiteral'](): Promise { + await Promise.resolve(); + } + async [Symbol.iterator](): Promise { + await Promise.resolve(); + } } `, errors: [ { data: { heritageTypeName: 'MyAbstractClass' }, - line: 7, + line: 12, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 15, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 18, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 21, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 24, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 27, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: ` + code: noFormat` abstract class MyAbstractClass { abstract setThing(): void; + abstract 1(): void; + abstract 2(): void; + abstract stringLiteral(): void; + abstract computedStringLiteral(): void; + abstract [Symbol.iterator](): void; } abstract class MyAbstractSubclassExtendsMyAbstractClass extends MyAbstractClass { abstract setThing(): Promise; + abstract 1(): Promise; + abstract [2](): Promise; + abstract 'stringLiteral'(): Promise; + abstract ['computedStringLiteral'](): Promise; + abstract [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyAbstractClass' }, - line: 7, + line: 12, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 13, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 14, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 15, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 16, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 17, messageId: 'voidReturnInheritedMethod', }, ], @@ -2076,54 +2344,170 @@ abstract class MyAbstractSubclassExtendsMyAbstractClass extends MyAbstractClass code: ` abstract class MyAbstractClass { abstract setThing(): void; + abstract setThing(): void; + abstract 1(): void; + abstract 2(): void; + abstract stringLiteral(): void; + abstract computedStringLiteral(): void; + abstract [Symbol.iterator](): void; } interface MyInterfaceExtendsMyAbstractClass extends MyAbstractClass { setThing(): Promise; + 1(): Promise; + [2](): Promise; + 'stringLiteral'(): Promise; + ['computedStringLiteral'](): Promise; + [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyAbstractClass' }, - line: 7, + line: 13, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 14, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 15, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 16, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 17, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyAbstractClass' }, + line: 18, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: ` + code: noFormat` interface MyInterface { setThing(): void; + 1(): void; + 2(): void; + stringLiteral(): void; + computedStringLiteral(): void; + [Symbol.iterator](): void; } class MyInterfaceSubclass implements MyInterface { async setThing(): Promise { await Promise.resolve(); } + async 1(): Promise { + await Promise.resolve(); + } + async [2](): Promise { + await Promise.resolve(); + } + async 'stringLiteral'(): Promise { + await Promise.resolve(); + } + async ['computedStringLiteral'](): Promise { + await Promise.resolve(); + } + async [Symbol.iterator](): Promise { + await Promise.resolve(); + } } `, errors: [ { data: { heritageTypeName: 'MyInterface' }, - line: 7, + line: 12, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 15, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 18, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 21, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 24, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 27, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: ` + code: noFormat` interface MyInterface { setThing(): void; + 1(): void; + 2(): void; + stringLiteral(): void; + computedStringLiteral(): void; + [Symbol.iterator](): void; } abstract class MyAbstractClassImplementsMyInterface implements MyInterface { abstract setThing(): Promise; + abstract 1(): Promise; + abstract [2](): Promise; + abstract 'stringLiteral'(): Promise; + abstract ['computedStringLiteral'](): Promise; + abstract [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyInterface' }, - line: 7, + line: 12, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 13, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 14, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 15, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 16, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 17, messageId: 'voidReturnInheritedMethod', }, ], @@ -2132,16 +2516,51 @@ abstract class MyAbstractClassImplementsMyInterface implements MyInterface { code: ` interface MyInterface { setThing(): void; + 1(): void; + 2(): void; + stringLiteral(): void; + computedStringLiteral(): void; + [Symbol.iterator](): void; } interface MySubInterface extends MyInterface { setThing(): Promise; + 1(): Promise; + [2](): Promise; + 'stringLiteral'(): Promise; + ['computedStringLiteral'](): Promise; + [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyInterface' }, - line: 7, + line: 12, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 13, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 14, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 15, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 16, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 17, messageId: 'voidReturnInheritedMethod', }, ], From 714f657447b5b2221ff9d2bcc1017905e6278269 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 21:30:33 +0200 Subject: [PATCH 06/20] update additional tests --- .../tests/rules/no-misused-promises.test.ts | 178 +++++++++++++++++- 1 file changed, 169 insertions(+), 9 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index f32400bbab48..d5fbb9955832 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -2566,38 +2566,133 @@ interface MySubInterface extends MyInterface { ], }, { - code: ` -type MyTypeIntersection = { setThing(): void } & { thing: number }; + code: noFormat` +type MyTypeIntersection = { + setThing(): void; + 1(): void; + 2(): void; + stringLiteral(): void; + computedStringLiteral(): void; + [Symbol.iterator](): void; +} & { thing: number }; class MyClassImplementsMyTypeIntersection implements MyTypeIntersection { thing = 1; async setThing(): Promise { await Promise.resolve(); } + async 1(): Promise { + await Promise.resolve(); + } + async [2](): Promise { + await Promise.resolve(); + } + async 'stringLiteral'(): Promise { + await Promise.resolve(); + } + async ['computedStringLiteral'](): Promise { + await Promise.resolve(); + } + async [Symbol.iterator](): Promise { + await Promise.resolve(); + } } `, errors: [ { data: { heritageTypeName: 'MyTypeIntersection' }, - line: 6, + line: 13, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyTypeIntersection' }, + line: 16, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyTypeIntersection' }, + line: 19, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyTypeIntersection' }, + line: 22, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyTypeIntersection' }, + line: 25, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyTypeIntersection' }, + line: 28, messageId: 'voidReturnInheritedMethod', }, ], }, { code: ` +type WhenTrue = { + setThing(): Promise; + 1(): Promise; + 2(): Promise; + stringLiteral(): Promise; + computedStringLiteral(): Promise; + [Symbol.iterator](): Promise; +}; + +type WhenFalse = { + setThing(): void; + 1(): void; + 2(): void; + stringLiteral(): void; + computedStringLiteral(): void; + [Symbol.iterator](): void; +}; + type MyGenericType = IsAsync extends true - ? { setThing(): Promise } - : { setThing(): void }; + ? WhenTrue + : WhenFalse; interface MyAsyncInterface extends MyGenericType { setThing(): Promise; + 1(): Promise; + [2](): Promise; + 'stringLiteral'(): Promise; + ['computedStringLiteral'](): Promise; + [Symbol.iterator](): Promise; } `, errors: [ { - data: { heritageTypeName: '{ setThing(): void; }' }, - line: 7, + data: { heritageTypeName: 'WhenFalse' }, + line: 25, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'WhenFalse' }, + line: 26, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'WhenFalse' }, + line: 27, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'WhenFalse' }, + line: 28, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'WhenFalse' }, + line: 29, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'WhenFalse' }, + line: 30, messageId: 'voidReturnInheritedMethod', }, ], @@ -2606,25 +2701,90 @@ interface MyAsyncInterface extends MyGenericType { code: ` interface MyInterface { setThing(): void; + 1(): void; + 2(): void; + stringLiteral(): void; + computedStringLiteral(): void; + [Symbol.iterator](): void; } interface MyOtherInterface { setThing(): void; + 1(): void; + 2(): void; + stringLiteral(): void; + computedStringLiteral(): void; + [Symbol.iterator](): void; } interface MyThirdInterface extends MyInterface, MyOtherInterface { setThing(): Promise; + 1(): Promise; + [2](): Promise; + 'stringLiteral'(): Promise; + ['computedStringLiteral'](): Promise; + [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyInterface' }, - line: 11, + line: 21, messageId: 'voidReturnInheritedMethod', }, { data: { heritageTypeName: 'MyOtherInterface' }, - line: 11, + line: 21, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 22, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyOtherInterface' }, + line: 22, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 23, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyOtherInterface' }, + line: 23, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 24, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyOtherInterface' }, + line: 24, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 25, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyOtherInterface' }, + line: 25, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 26, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyOtherInterface' }, + line: 26, messageId: 'voidReturnInheritedMethod', }, ], From a31559dd036b72875d0d2444eaf90e21000695d7 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 21:36:11 +0200 Subject: [PATCH 07/20] update additional tests --- .../tests/rules/no-misused-promises.test.ts | 185 +++++++++++++++++- 1 file changed, 180 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index d5fbb9955832..60c797642693 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -2795,62 +2795,237 @@ class MyClass { setThing(): void { return; } + 1(): void { + return; + } + 2(): void { + return; + } + stringLiteral(): void { + return; + } + computedStringLiteral(): void { + return; + } + [Symbol.iterator](): void { + return; + } } class MyOtherClass { setThing(): void { return; } + 1(): void { + return; + } + 2(): void { + return; + } + stringLiteral(): void { + return; + } + computedStringLiteral(): void { + return; + } + [Symbol.iterator](): void { + return; + } } interface MyInterface extends MyClass, MyOtherClass { setThing(): Promise; + 1(): Promise; + [2](): Promise; + 'stringLiteral'(): Promise; + ['computedStringLiteral'](): Promise; + [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyClass' }, - line: 15, + line: 45, messageId: 'voidReturnInheritedMethod', }, { data: { heritageTypeName: 'MyOtherClass' }, - line: 15, + line: 45, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 46, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyOtherClass' }, + line: 46, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 47, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyOtherClass' }, + line: 47, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 48, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyOtherClass' }, + line: 48, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 49, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyOtherClass' }, + line: 49, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 50, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyOtherClass' }, + line: 50, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: ` + code: noFormat` interface MyAsyncInterface { setThing(): Promise; + 1(): Promise; + 2(): Promise; + stringLiteral(): Promise; + computedStringLiteral(): Promise; + [Symbol.iterator](): Promise; } interface MySyncInterface { setThing(): void; + 1(): void; + 2(): void; + stringLiteral(): void; + computedStringLiteral(): void; + [Symbol.iterator](): void; } class MyClass { setThing(): void { return; } + 1(): void { + return; + } + 2(): void { + return; + } + stringLiteral(): void { + return; + } + computedStringLiteral(): void { + return; + } + [Symbol.iterator](): void { + return; + } } class MySubclass extends MyClass implements MyAsyncInterface, MySyncInterface { async setThing(): Promise { await Promise.resolve(); } + async 1(): Promise { + await Promise.resolve(); + } + async [2](): Promise { + await Promise.resolve(); + } + async 'stringLiteral'(): Promise { + await Promise.resolve(); + } + async ['computedStringLiteral'](): Promise { + await Promise.resolve(); + } + async [Symbol.iterator](): Promise { + await Promise.resolve(); + } } `, errors: [ { data: { heritageTypeName: 'MyClass' }, - line: 17, + line: 42, messageId: 'voidReturnInheritedMethod', }, { data: { heritageTypeName: 'MySyncInterface' }, - line: 17, + line: 42, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 45, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MySyncInterface' }, + line: 45, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 48, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MySyncInterface' }, + line: 48, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 51, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MySyncInterface' }, + line: 51, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 54, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MySyncInterface' }, + line: 54, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClass' }, + line: 57, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MySyncInterface' }, + line: 57, messageId: 'voidReturnInheritedMethod', }, ], From a12f0a05cddfd4c78163d3bf3b83fb0fab55cb7d Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 21:48:39 +0200 Subject: [PATCH 08/20] update additional tests --- .../tests/rules/no-misused-promises.test.ts | 150 +++++++++++++++++- 1 file changed, 145 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index 60c797642693..c9f549c0db2f 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -3031,43 +3031,143 @@ class MySubclass extends MyClass implements MyAsyncInterface, MySyncInterface { ], }, { - code: ` + code: noFormat` interface MyInterface { setThing(): void; + 1(): void; + 2(): void; + stringLiteral(): void; + computedStringLiteral(): void; + [Symbol.iterator](): void; } const MyClassExpressionExtendsMyClass = class implements MyInterface { setThing(): Promise { await Promise.resolve(); } + 1(): Promise { + await Promise.resolve(); + } + [2](): Promise { + await Promise.resolve(); + } + 'stringLiteral'(): Promise { + await Promise.resolve(); + } + ['computedStringLiteral'](): Promise { + await Promise.resolve(); + } + [Symbol.iterator](): Promise { + await Promise.resolve(); + } }; `, errors: [ { data: { heritageTypeName: 'MyInterface' }, - line: 7, + line: 12, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 15, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 18, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 21, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 24, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyInterface' }, + line: 27, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: ` + code: noFormat` const MyClassExpression = class { setThing(): void { return; } + 1(): void { + return; + } + 2(): void { + return; + } + stringLiteral(): void { + return; + } + computedStringLiteral(): void { + return; + } + [Symbol.iterator](): void { + return; + } }; class MyClassExtendsMyClassExpression extends MyClassExpression { async setThing(): Promise { await Promise.resolve(); } + async 1(): Promise { + await Promise.resolve(); + } + async [2](): Promise { + await Promise.resolve(); + } + async 'stringLiteral'(): Promise { + await Promise.resolve(); + } + async ['computedStringLiteral'](): Promise { + await Promise.resolve(); + } + async [Symbol.iterator](): Promise { + await Promise.resolve(); + } } `, errors: [ { data: { heritageTypeName: 'MyClassExpression' }, - line: 9, + line: 24, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClassExpression' }, + line: 27, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClassExpression' }, + line: 30, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClassExpression' }, + line: 33, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClassExpression' }, + line: 36, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'MyClassExpression' }, + line: 39, messageId: 'voidReturnInheritedMethod', }, ], @@ -3078,17 +3178,57 @@ const MyClassExpression = class { setThing(): void { return; } + 1(): void { + return; + } + 2(): void { + return; + } + stringLiteral(): void { + return; + } + computedStringLiteral(): void { + return; + } + [Symbol.iterator](): void { + return; + } }; type MyClassExpressionType = typeof MyClassExpression; interface MyInterfaceExtendsMyClassExpression extends MyClassExpressionType { setThing(): Promise; + 1(): Promise; + [2](): Promise; + 'stringLiteral'(): Promise; + ['computedStringLiteral'](): Promise; + [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'typeof MyClassExpression' }, - line: 10, + line: 25, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'typeof MyClassExpression' }, + line: 26, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'typeof MyClassExpression' }, + line: 27, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'typeof MyClassExpression' }, + line: 28, + messageId: 'voidReturnInheritedMethod', + }, + { + data: { heritageTypeName: 'typeof MyClassExpression' }, + line: 29, messageId: 'voidReturnInheritedMethod', }, ], From a8d14c1b3d3c9e05b558e9637f551602087aff16 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 21:52:58 +0200 Subject: [PATCH 09/20] update additional tests --- .../tests/rules/no-misused-promises.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index c9f549c0db2f..f03c911cd684 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -2033,7 +2033,7 @@ class MyClass { computedStringLiteral(): void { return; } - [Symbol.iterator](): void { + [Symbol.asyncIterator](): void { return; } } @@ -2054,7 +2054,7 @@ class MySubclassExtendsMyClass extends MyClass { async ['computedStringLiteral'](): Promise { await Promise.resolve(); } - async [Symbol.iterator](): Promise { + async [Symbol.asyncIterator](): Promise { await Promise.resolve(); } } @@ -2230,7 +2230,7 @@ abstract class MyAbstractClass { abstract 2(): void; abstract stringLiteral(): void; abstract computedStringLiteral(): void; - abstract [Symbol.iterator](): void; + abstract [Symbol.asyncIterator](): void; } class MySubclassExtendsMyAbstractClass extends MyAbstractClass { @@ -2249,7 +2249,7 @@ class MySubclassExtendsMyAbstractClass extends MyAbstractClass { async ['computedStringLiteral'](): Promise { await Promise.resolve(); } - async [Symbol.iterator](): Promise { + async [Symbol.asyncIterator](): Promise { await Promise.resolve(); } } @@ -3113,7 +3113,7 @@ const MyClassExpression = class { computedStringLiteral(): void { return; } - [Symbol.iterator](): void { + [Symbol.asyncIterator](): void { return; } }; @@ -3134,7 +3134,7 @@ class MyClassExtendsMyClassExpression extends MyClassExpression { async ['computedStringLiteral'](): Promise { await Promise.resolve(); } - async [Symbol.iterator](): Promise { + async [Symbol.asyncIterator](): Promise { await Promise.resolve(); } } From 07b9daacf746714f124421615fb7e9d97e9e561a Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 23:12:48 +0200 Subject: [PATCH 10/20] simplify test cases, check static properties in isolation --- .../tests/rules/no-misused-promises.test.ts | 1401 ++++------------- 1 file changed, 300 insertions(+), 1101 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index f03c911cd684..dd559fb74fd3 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -1066,6 +1066,98 @@ declare const useCallback: unknown>( ) => T; useCallback(async () => {}); `, + { + code: noFormat` +const staticSymbol = Symbol.for('static symbol'); + +type O = { + 1: () => void; + 2: () => void; + stringLiteral: () => void; + computedStringLiteral: () => void; + [Symbol.iterator]: () => void; + [staticSymbol]: () => void; +}; + +const obj: O = { + 1() {}, + [2]() {}, + 'stringLiteral'() {}, + ['computedStringLiteral']() {}, + [Symbol.iterator]() {}, + [staticSymbol]() {} +}; + `, + }, + { + code: noFormat` +const staticSymbol = Symbol.for('static symbol'); + +type O = { + 1: () => Promise; + 2: () => Promise; + stringLiteral: () => Promise; + computedStringLiteral: () => Promise; + [Symbol.iterator]: () => Promise; + [staticSymbol]: () => Promise; +}; + +const obj: O = { + async 1() {}, + async [2]() {}, + async 'stringLiteral'() {}, + async ['computedStringLiteral']() {}, + async [Symbol.iterator]() {}, + async [staticSymbol]() {} +}; + `, + }, + { + code: noFormat` +const staticSymbol = Symbol.for('static symbol'); + +class MyClass { + 1(): void {} + 2(): void {} + stringLiteral(): void {} + computedStringLiteral(): void {} + [Symbol.asyncIterator](): void {} + [staticSymbol](): void {} +} + +class MySubclassExtendsMyClass extends MyClass { + 1(): void {} + [2](): void {} + 'stringLiteral'(): void {} + ['computedStringLiteral'](): void {} + [Symbol.asyncIterator](): void {} + [staticSymbol](): void {} +} + `, + }, + { + code: noFormat` +const staticSymbol = Symbol.for('static symbol'); + +class MyClass { + 1(): Promise {} + 2(): Promise {} + stringLiteral(): Promise {} + computedStringLiteral(): Promise {} + [Symbol.asyncIterator](): Promise {} + [staticSymbol](): Promise {} +} + +class MySubclassExtendsMyClass extends MyClass { + async 1(): Promise {} + async [2](): Promise {} + async 'stringLiteral'(): Promise {} + async ['computedStringLiteral'](): Promise {} + async [Symbol.asyncIterator](): Promise {} + async [staticSymbol](): Promise {} +} + `, + }, ], invalid: [ @@ -1383,125 +1475,43 @@ const g = async () => 1, { code: ` const obj: { - identifier?: () => void; - 1?: () => void; - computedStringLiteral?: () => void; - [Symbol.iterator]?: () => void; + f?: () => void; } = {}; -obj.identifier = async () => { - return 0; -}; -obj[1] = async () => { - return 0; -}; -obj['computedStringLiteral'] = async () => { - return 0; -}; -obj[Symbol.iterator] = async () => { +obj.f = async () => { return 0; }; `, errors: [ { - line: 8, - messageId: 'voidReturnVariable', - }, - { - line: 11, - messageId: 'voidReturnVariable', - }, - { - line: 14, - messageId: 'voidReturnVariable', - }, - { - line: 17, + line: 5, messageId: 'voidReturnVariable', }, ], }, { - code: noFormat` -type O = { - identifier: () => void; - 1: () => void; - stringLiteral: () => void; - computedStringLiteral: () => void; - [Symbol.iterator]: () => void; -}; + code: ` +type O = { f: () => void }; const obj: O = { - identifier: async () => 'foo', - [1]: async () => 'foo', - 'stringLiteral': async () => 'foo', - ['computedStringLiteral']: async () => 'foo', - [Symbol.iterator]: async () => 'foo', + f: async () => 'foo', }; `, errors: [ { - line: 10, - messageId: 'voidReturnProperty', - }, - { - line: 11, - messageId: 'voidReturnProperty', - }, - { - line: 12, - messageId: 'voidReturnProperty', - }, - { - line: 13, - messageId: 'voidReturnProperty', - }, - { - line: 14, + line: 4, messageId: 'voidReturnProperty', }, ], }, { - code: noFormat` -type O = { - identifier: () => void; - 1: () => void; - 2: () => void; - stringLiteral: () => void; - computedStringLiteral: () => void; - [Symbol.iterator]: () => void; -}; + code: ` +type O = { f: () => void }; const obj: O = { - identifier: async () => 'foo', - 1: async () => 'foo', - [2]: async () => 'foo', - 'stringLiteral': async () => 'foo', - ['computedStringLiteral']: async () => 'foo', - [Symbol.iterator]: async () => 'foo', + f: async () => 'foo', }; `, errors: [ { - line: 11, - messageId: 'voidReturnProperty', - }, - { - line: 12, - messageId: 'voidReturnProperty', - }, - { - line: 13, - messageId: 'voidReturnProperty', - }, - { - line: 14, - messageId: 'voidReturnProperty', - }, - { - line: 15, - messageId: 'voidReturnProperty', - }, - { - line: 16, + line: 4, messageId: 'voidReturnProperty', }, ], @@ -1523,75 +1533,24 @@ const obj: O = { ], }, { - code: noFormat` -type O = { - identifier: () => void; - 1: () => void; - 2: () => void; - stringLiteral: () => void; - computedStringLiteral: () => void; - [Symbol.iterator]: () => void; -}; + code: ` +type O = { f: () => void }; const obj: O = { - async identifier() { - return 0; - }, - async 1() { - return 0; - }, - async [2]() { - return 0; - }, - async 'stringLiteral'() { - return 0; - }, - async ['computedStringLiteral']() { - return 0; - }, - async [Symbol.iterator]() { + async f() { return 0; }, }; `, errors: [ { - line: 11, - messageId: 'voidReturnProperty', - }, - { - line: 14, - messageId: 'voidReturnProperty', - }, - { - line: 17, - messageId: 'voidReturnProperty', - }, - { - line: 20, - messageId: 'voidReturnProperty', - }, - { - line: 23, - messageId: 'voidReturnProperty', - }, - { - line: 26, + line: 4, messageId: 'voidReturnProperty', }, ], }, { - code: noFormat` -type O = { - f: () => void; - g: () => void; - h: () => void; - 1: () => void; - 2: () => void; - stringLiteral: () => void; - computedStringLiteral: () => void; - [Symbol.iterator]: () => void; -}; + code: ` +type O = { f: () => void; g: () => void; h: () => void }; function f(): O { const h = async () => 0; return { @@ -1600,55 +1559,20 @@ function f(): O { }, g: async () => 0, h, - async 1() { - return 123; - }, - async [2]() { - return 123; - }, - async 'stringLiteral'() { - return 123; - }, - async ['computedStringLiteral']() { - return 123; - }, - async [Symbol.iterator]() { - return 123; - }, }; } `, errors: [ { - line: 15, - messageId: 'voidReturnProperty', - }, - { - line: 18, - messageId: 'voidReturnProperty', - }, - { - line: 19, - messageId: 'voidReturnProperty', - }, - { - line: 20, - messageId: 'voidReturnProperty', - }, - { - line: 23, - messageId: 'voidReturnProperty', - }, - { - line: 26, + line: 6, messageId: 'voidReturnProperty', }, { - line: 29, + line: 9, messageId: 'voidReturnProperty', }, { - line: 32, + line: 10, messageId: 'voidReturnProperty', }, ], @@ -2016,143 +1940,43 @@ consume(...cbs); errors: [{ line: 4, messageId: 'voidReturnArgument' }], }, { - code: noFormat` + code: ` class MyClass { setThing(): void { return; } - 1(): void { - return; - } - 2(): void { - return; - } - stringLiteral(): void { - return; - } - computedStringLiteral(): void { - return; - } - [Symbol.asyncIterator](): void { - return; - } } class MySubclassExtendsMyClass extends MyClass { async setThing(): Promise { await Promise.resolve(); } - async 1(): Promise { - await Promise.resolve(); - } - async [2](): Promise { - await Promise.resolve(); - } - async 'stringLiteral'(): Promise { - await Promise.resolve(); - } - async ['computedStringLiteral'](): Promise { - await Promise.resolve(); - } - async [Symbol.asyncIterator](): Promise { - await Promise.resolve(); - } } `, errors: [ { data: { heritageTypeName: 'MyClass' }, - line: 24, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 27, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 30, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 33, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 36, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 39, + line: 9, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: noFormat` + code: ` class MyClass { setThing(): void { return; } - 1(): void { - return; - } - 2(): void { - return; - } - stringLiteral(): void { - return; - } - computedStringLiteral(): void { - return; - } - [Symbol.iterator](): void { - return; - } } abstract class MyAbstractClassExtendsMyClass extends MyClass { abstract setThing(): Promise; - abstract 1(): Promise; - abstract [2](): Promise; - abstract 'stringLiteral'(): Promise; - abstract ['computedStringLiteral'](): Promise; - abstract [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyClass' }, - line: 24, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 25, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 26, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 27, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 28, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 29, + line: 9, messageId: 'voidReturnInheritedMethod', }, ], @@ -2163,179 +1987,54 @@ class MyClass { setThing(): void { return; } - 1(): void { - return; - } - 2(): void { - return; - } - stringLiteral(): void { - return; - } - computedStringLiteral(): void { - return; - } - [Symbol.iterator](): void { - return; - } } interface MyInterfaceExtendsMyClass extends MyClass { setThing(): Promise; - 1(): Promise; - [2](): Promise; - 'stringLiteral'(): Promise; - ['computedStringLiteral'](): Promise; - [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyClass' }, - line: 24, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 25, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 26, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 27, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 28, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 29, + line: 9, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: noFormat` + code: ` abstract class MyAbstractClass { abstract setThing(): void; - abstract 1(): void; - abstract 2(): void; - abstract stringLiteral(): void; - abstract computedStringLiteral(): void; - abstract [Symbol.asyncIterator](): void; } class MySubclassExtendsMyAbstractClass extends MyAbstractClass { async setThing(): Promise { await Promise.resolve(); } - async 1(): Promise { - await Promise.resolve(); - } - async [2](): Promise { - await Promise.resolve(); - } - async 'stringLiteral'(): Promise { - await Promise.resolve(); - } - async ['computedStringLiteral'](): Promise { - await Promise.resolve(); - } - async [Symbol.asyncIterator](): Promise { - await Promise.resolve(); - } } `, errors: [ { data: { heritageTypeName: 'MyAbstractClass' }, - line: 12, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 15, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 18, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 21, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 24, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 27, + line: 7, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: noFormat` + code: ` abstract class MyAbstractClass { abstract setThing(): void; - abstract 1(): void; - abstract 2(): void; - abstract stringLiteral(): void; - abstract computedStringLiteral(): void; - abstract [Symbol.iterator](): void; } abstract class MyAbstractSubclassExtendsMyAbstractClass extends MyAbstractClass { abstract setThing(): Promise; - abstract 1(): Promise; - abstract [2](): Promise; - abstract 'stringLiteral'(): Promise; - abstract ['computedStringLiteral'](): Promise; - abstract [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyAbstractClass' }, - line: 12, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 13, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 14, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 15, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 16, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 17, + line: 7, messageId: 'voidReturnInheritedMethod', }, ], @@ -2344,170 +2043,54 @@ abstract class MyAbstractSubclassExtendsMyAbstractClass extends MyAbstractClass code: ` abstract class MyAbstractClass { abstract setThing(): void; - abstract setThing(): void; - abstract 1(): void; - abstract 2(): void; - abstract stringLiteral(): void; - abstract computedStringLiteral(): void; - abstract [Symbol.iterator](): void; } interface MyInterfaceExtendsMyAbstractClass extends MyAbstractClass { setThing(): Promise; - 1(): Promise; - [2](): Promise; - 'stringLiteral'(): Promise; - ['computedStringLiteral'](): Promise; - [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyAbstractClass' }, - line: 13, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 14, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 15, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 16, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 17, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyAbstractClass' }, - line: 18, + line: 7, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: noFormat` + code: ` interface MyInterface { setThing(): void; - 1(): void; - 2(): void; - stringLiteral(): void; - computedStringLiteral(): void; - [Symbol.iterator](): void; } class MyInterfaceSubclass implements MyInterface { async setThing(): Promise { await Promise.resolve(); } - async 1(): Promise { - await Promise.resolve(); - } - async [2](): Promise { - await Promise.resolve(); - } - async 'stringLiteral'(): Promise { - await Promise.resolve(); - } - async ['computedStringLiteral'](): Promise { - await Promise.resolve(); - } - async [Symbol.iterator](): Promise { - await Promise.resolve(); - } } `, errors: [ { data: { heritageTypeName: 'MyInterface' }, - line: 12, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 15, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 18, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 21, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 24, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 27, + line: 7, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: noFormat` + code: ` interface MyInterface { setThing(): void; - 1(): void; - 2(): void; - stringLiteral(): void; - computedStringLiteral(): void; - [Symbol.iterator](): void; } abstract class MyAbstractClassImplementsMyInterface implements MyInterface { abstract setThing(): Promise; - abstract 1(): Promise; - abstract [2](): Promise; - abstract 'stringLiteral'(): Promise; - abstract ['computedStringLiteral'](): Promise; - abstract [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyInterface' }, - line: 12, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 13, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 14, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 15, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 16, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 17, + line: 7, messageId: 'voidReturnInheritedMethod', }, ], @@ -2516,183 +2099,53 @@ abstract class MyAbstractClassImplementsMyInterface implements MyInterface { code: ` interface MyInterface { setThing(): void; - 1(): void; - 2(): void; - stringLiteral(): void; - computedStringLiteral(): void; - [Symbol.iterator](): void; } interface MySubInterface extends MyInterface { setThing(): Promise; - 1(): Promise; - [2](): Promise; - 'stringLiteral'(): Promise; - ['computedStringLiteral'](): Promise; - [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyInterface' }, - line: 12, + line: 7, messageId: 'voidReturnInheritedMethod', }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 13, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 14, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 15, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 16, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 17, - messageId: 'voidReturnInheritedMethod', - }, - ], - }, - { - code: noFormat` -type MyTypeIntersection = { - setThing(): void; - 1(): void; - 2(): void; - stringLiteral(): void; - computedStringLiteral(): void; - [Symbol.iterator](): void; -} & { thing: number }; - -class MyClassImplementsMyTypeIntersection implements MyTypeIntersection { - thing = 1; - async setThing(): Promise { - await Promise.resolve(); - } - async 1(): Promise { - await Promise.resolve(); - } - async [2](): Promise { - await Promise.resolve(); - } - async 'stringLiteral'(): Promise { - await Promise.resolve(); - } - async ['computedStringLiteral'](): Promise { - await Promise.resolve(); - } - async [Symbol.iterator](): Promise { - await Promise.resolve(); - } -} - `, - errors: [ + ], + }, + { + code: ` +type MyTypeIntersection = { setThing(): void } & { thing: number }; + +class MyClassImplementsMyTypeIntersection implements MyTypeIntersection { + thing = 1; + async setThing(): Promise { + await Promise.resolve(); + } +} + `, + errors: [ { data: { heritageTypeName: 'MyTypeIntersection' }, - line: 13, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyTypeIntersection' }, - line: 16, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyTypeIntersection' }, - line: 19, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyTypeIntersection' }, - line: 22, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyTypeIntersection' }, - line: 25, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyTypeIntersection' }, - line: 28, + line: 6, messageId: 'voidReturnInheritedMethod', }, ], }, { code: ` -type WhenTrue = { - setThing(): Promise; - 1(): Promise; - 2(): Promise; - stringLiteral(): Promise; - computedStringLiteral(): Promise; - [Symbol.iterator](): Promise; -}; - -type WhenFalse = { - setThing(): void; - 1(): void; - 2(): void; - stringLiteral(): void; - computedStringLiteral(): void; - [Symbol.iterator](): void; -}; - type MyGenericType = IsAsync extends true - ? WhenTrue - : WhenFalse; + ? { setThing(): Promise } + : { setThing(): void }; interface MyAsyncInterface extends MyGenericType { setThing(): Promise; - 1(): Promise; - [2](): Promise; - 'stringLiteral'(): Promise; - ['computedStringLiteral'](): Promise; - [Symbol.iterator](): Promise; } `, errors: [ { - data: { heritageTypeName: 'WhenFalse' }, - line: 25, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'WhenFalse' }, - line: 26, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'WhenFalse' }, - line: 27, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'WhenFalse' }, - line: 28, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'WhenFalse' }, - line: 29, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'WhenFalse' }, - line: 30, + data: { heritageTypeName: '{ setThing(): void; }' }, + line: 7, messageId: 'voidReturnInheritedMethod', }, ], @@ -2701,90 +2154,25 @@ interface MyAsyncInterface extends MyGenericType { code: ` interface MyInterface { setThing(): void; - 1(): void; - 2(): void; - stringLiteral(): void; - computedStringLiteral(): void; - [Symbol.iterator](): void; } interface MyOtherInterface { setThing(): void; - 1(): void; - 2(): void; - stringLiteral(): void; - computedStringLiteral(): void; - [Symbol.iterator](): void; } interface MyThirdInterface extends MyInterface, MyOtherInterface { setThing(): Promise; - 1(): Promise; - [2](): Promise; - 'stringLiteral'(): Promise; - ['computedStringLiteral'](): Promise; - [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyInterface' }, - line: 21, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyOtherInterface' }, - line: 21, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 22, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyOtherInterface' }, - line: 22, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 23, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyOtherInterface' }, - line: 23, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 24, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyOtherInterface' }, - line: 24, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 25, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyOtherInterface' }, - line: 25, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 26, + line: 11, messageId: 'voidReturnInheritedMethod', }, { data: { heritageTypeName: 'MyOtherInterface' }, - line: 26, + line: 11, messageId: 'voidReturnInheritedMethod', }, ], @@ -2795,379 +2183,104 @@ class MyClass { setThing(): void { return; } - 1(): void { - return; - } - 2(): void { - return; - } - stringLiteral(): void { - return; - } - computedStringLiteral(): void { - return; - } - [Symbol.iterator](): void { - return; - } } class MyOtherClass { setThing(): void { return; } - 1(): void { - return; - } - 2(): void { - return; - } - stringLiteral(): void { - return; - } - computedStringLiteral(): void { - return; - } - [Symbol.iterator](): void { - return; - } } interface MyInterface extends MyClass, MyOtherClass { setThing(): Promise; - 1(): Promise; - [2](): Promise; - 'stringLiteral'(): Promise; - ['computedStringLiteral'](): Promise; - [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'MyClass' }, - line: 45, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyOtherClass' }, - line: 45, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 46, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyOtherClass' }, - line: 46, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 47, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyOtherClass' }, - line: 47, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 48, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyOtherClass' }, - line: 48, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 49, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyOtherClass' }, - line: 49, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 50, + line: 15, messageId: 'voidReturnInheritedMethod', }, { data: { heritageTypeName: 'MyOtherClass' }, - line: 50, + line: 15, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: noFormat` + code: ` interface MyAsyncInterface { setThing(): Promise; - 1(): Promise; - 2(): Promise; - stringLiteral(): Promise; - computedStringLiteral(): Promise; - [Symbol.iterator](): Promise; } interface MySyncInterface { - setThing(): void; - 1(): void; - 2(): void; - stringLiteral(): void; - computedStringLiteral(): void; - [Symbol.iterator](): void; -} - -class MyClass { - setThing(): void { - return; - } - 1(): void { - return; - } - 2(): void { - return; - } - stringLiteral(): void { - return; - } - computedStringLiteral(): void { - return; - } - [Symbol.iterator](): void { - return; - } -} - -class MySubclass extends MyClass implements MyAsyncInterface, MySyncInterface { - async setThing(): Promise { - await Promise.resolve(); - } - async 1(): Promise { - await Promise.resolve(); - } - async [2](): Promise { - await Promise.resolve(); - } - async 'stringLiteral'(): Promise { - await Promise.resolve(); - } - async ['computedStringLiteral'](): Promise { - await Promise.resolve(); - } - async [Symbol.iterator](): Promise { - await Promise.resolve(); - } -} - `, - errors: [ - { - data: { heritageTypeName: 'MyClass' }, - line: 42, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MySyncInterface' }, - line: 42, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 45, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MySyncInterface' }, - line: 45, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 48, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MySyncInterface' }, - line: 48, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 51, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MySyncInterface' }, - line: 51, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClass' }, - line: 54, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MySyncInterface' }, - line: 54, - messageId: 'voidReturnInheritedMethod', - }, + setThing(): void; +} + +class MyClass { + setThing(): void { + return; + } +} + +class MySubclass extends MyClass implements MyAsyncInterface, MySyncInterface { + async setThing(): Promise { + await Promise.resolve(); + } +} + `, + errors: [ { data: { heritageTypeName: 'MyClass' }, - line: 57, + line: 17, messageId: 'voidReturnInheritedMethod', }, { data: { heritageTypeName: 'MySyncInterface' }, - line: 57, + line: 17, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: noFormat` + code: ` interface MyInterface { setThing(): void; - 1(): void; - 2(): void; - stringLiteral(): void; - computedStringLiteral(): void; - [Symbol.iterator](): void; } const MyClassExpressionExtendsMyClass = class implements MyInterface { setThing(): Promise { await Promise.resolve(); } - 1(): Promise { - await Promise.resolve(); - } - [2](): Promise { - await Promise.resolve(); - } - 'stringLiteral'(): Promise { - await Promise.resolve(); - } - ['computedStringLiteral'](): Promise { - await Promise.resolve(); - } - [Symbol.iterator](): Promise { - await Promise.resolve(); - } }; `, errors: [ { data: { heritageTypeName: 'MyInterface' }, - line: 12, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 15, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 18, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 21, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 24, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyInterface' }, - line: 27, + line: 7, messageId: 'voidReturnInheritedMethod', }, ], }, { - code: noFormat` + code: ` const MyClassExpression = class { setThing(): void { return; } - 1(): void { - return; - } - 2(): void { - return; - } - stringLiteral(): void { - return; - } - computedStringLiteral(): void { - return; - } - [Symbol.asyncIterator](): void { - return; - } }; class MyClassExtendsMyClassExpression extends MyClassExpression { async setThing(): Promise { await Promise.resolve(); } - async 1(): Promise { - await Promise.resolve(); - } - async [2](): Promise { - await Promise.resolve(); - } - async 'stringLiteral'(): Promise { - await Promise.resolve(); - } - async ['computedStringLiteral'](): Promise { - await Promise.resolve(); - } - async [Symbol.asyncIterator](): Promise { - await Promise.resolve(); - } } `, errors: [ { data: { heritageTypeName: 'MyClassExpression' }, - line: 24, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClassExpression' }, - line: 27, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClassExpression' }, - line: 30, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClassExpression' }, - line: 33, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClassExpression' }, - line: 36, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'MyClassExpression' }, - line: 39, + line: 9, messageId: 'voidReturnInheritedMethod', }, ], @@ -3178,57 +2291,17 @@ const MyClassExpression = class { setThing(): void { return; } - 1(): void { - return; - } - 2(): void { - return; - } - stringLiteral(): void { - return; - } - computedStringLiteral(): void { - return; - } - [Symbol.iterator](): void { - return; - } }; type MyClassExpressionType = typeof MyClassExpression; interface MyInterfaceExtendsMyClassExpression extends MyClassExpressionType { setThing(): Promise; - 1(): Promise; - [2](): Promise; - 'stringLiteral'(): Promise; - ['computedStringLiteral'](): Promise; - [Symbol.iterator](): Promise; } `, errors: [ { data: { heritageTypeName: 'typeof MyClassExpression' }, - line: 25, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'typeof MyClassExpression' }, - line: 26, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'typeof MyClassExpression' }, - line: 27, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'typeof MyClassExpression' }, - line: 28, - messageId: 'voidReturnInheritedMethod', - }, - { - data: { heritageTypeName: 'typeof MyClassExpression' }, - line: 29, + line: 10, messageId: 'voidReturnInheritedMethod', }, ], @@ -3448,5 +2521,131 @@ arrayFn<() => void>( }, ], }, + { + code: noFormat` +const staticSymbol = Symbol.for('static symbol'); + +type O = { + 1: () => void; + 2: () => void; + stringLiteral: () => void; + computedStringLiteral: () => void; + [Symbol.iterator]: () => void; + [staticSymbol]: () => void; +}; + +const obj: O = { + async 1() { + return 0; + }, + async [2]() { + return 0; + }, + async 'stringLiteral'() { + return 0; + }, + async ['computedStringLiteral']() { + return 0; + }, + async [Symbol.iterator]() { + return 0; + }, + async [staticSymbol]() { + return 0; + } +}; + `, + errors: [ + { + line: 14, + messageId: 'voidReturnProperty', + }, + { + line: 17, + messageId: 'voidReturnProperty', + }, + { + line: 20, + messageId: 'voidReturnProperty', + }, + { + line: 23, + messageId: 'voidReturnProperty', + }, + { + line: 26, + messageId: 'voidReturnProperty', + }, + ], + }, + { + code: noFormat` +const staticSymbol = Symbol.for('static symbol'); + +class MyClass { + 1(): void { + return; + } + 2(): void { + return; + } + stringLiteral(): void { + return; + } + computedStringLiteral(): void { + return; + } + [Symbol.asyncIterator](): void { + return; + } + [staticSymbol](): void { + return; + } +} + +class MySubclassExtendsMyClass extends MyClass { + async 1(): Promise { + await Promise.resolve(); + } + async [2](): Promise { + await Promise.resolve(); + } + async 'stringLiteral'(): Promise { + await Promise.resolve(); + } + async ['computedStringLiteral'](): Promise { + await Promise.resolve(); + } + async [Symbol.asyncIterator](): Promise { + await Promise.resolve(); + } + async [staticSymbol](): Promise { + await Promise.resolve(); + } +} + `, + errors: [ + { + line: 26, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 29, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 32, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 35, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 38, + messageId: 'voidReturnInheritedMethod', + }, + ], + }, ], }); From e00a2b0a0f83752cfbcba8fc4d3a0ee321a8b8f8 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Fri, 8 Nov 2024 23:24:46 +0200 Subject: [PATCH 11/20] expand tests --- .../tests/rules/no-misused-promises.test.ts | 105 +++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index dd559fb74fd3..5631b14e2044 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -1108,7 +1108,8 @@ const obj: O = { async 'stringLiteral'() {}, async ['computedStringLiteral']() {}, async [Symbol.iterator]() {}, - async [staticSymbol]() {} + async [staticSymbol]() {}, + async ownProperty() {}, }; `, }, @@ -1132,6 +1133,7 @@ class MySubclassExtendsMyClass extends MyClass { ['computedStringLiteral'](): void {} [Symbol.asyncIterator](): void {} [staticSymbol](): void {} + ownProperty(): void {} } `, }, @@ -1155,6 +1157,55 @@ class MySubclassExtendsMyClass extends MyClass { async ['computedStringLiteral'](): Promise {} async [Symbol.asyncIterator](): Promise {} async [staticSymbol](): Promise {} + async ownProperty(): Promise {} +} + `, + }, + { + code: noFormat` +const staticSymbol = Symbol.for('static symbol'); + +interface MyInterface { + 1(): void; + 2(): void; + stringLiteral(): void; + computedStringLiteral(): void; + [Symbol.asyncIterator](): void; + [staticSymbol](): void; +} + +class MySubinterfaceExtendsMyInterface extends MyInterface { + async 1(): void; + async [2](): void; + async 'stringLiteral'(): void; + async ['computedStringLiteral'](): void; + async [Symbol.asyncIterator](): void; + async [staticSymbol](): void; + async ownProperty(): void; +} + `, + }, + { + code: noFormat` +const staticSymbol = Symbol.for('static symbol'); + +interface MyInterface { + 1(): Promise; + 2(): Promise; + stringLiteral(): Promise; + computedStringLiteral(): Promise; + [Symbol.asyncIterator](): Promise; + [staticSymbol](): Promise; +} + +class MySubinterfaceExtendsMyInterface extends MyInterface { + async 1(): Promise; + async [2](): Promise; + async 'stringLiteral'(): Promise; + async ['computedStringLiteral'](): Promise; + async [Symbol.asyncIterator](): Promise; + async [staticSymbol](): Promise; + async ownProperty(): Promise; } `, }, @@ -2552,6 +2603,9 @@ const obj: O = { }, async [staticSymbol]() { return 0; + }, + async ownProperty() { + return 0; } }; `, @@ -2622,6 +2676,9 @@ class MySubclassExtendsMyClass extends MyClass { async [staticSymbol](): Promise { await Promise.resolve(); } + async ownProperty(): Promise { + await Promise.resolve(); + } } `, errors: [ @@ -2647,5 +2704,51 @@ class MySubclassExtendsMyClass extends MyClass { }, ], }, + { + code: noFormat` +const staticSymbol = Symbol.for('static symbol'); + +interface MyInterface { + 1(): void + 2(): void + stringLiteral(): void + computedStringLiteral(): void + [Symbol.asyncIterator](): void + [staticSymbol](): void +} + +interface MySubinterfaceExtendsMyInterface extends MyInterface { + 1(): Promise + [2](): Promise + 'stringLiteral'(): Promise + ['computedStringLiteral'](): Promise + [Symbol.asyncIterator](): Promise + [staticSymbol](): Promise + ownProperty(): Promise +} + `, + errors: [ + { + line: 14, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 15, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 16, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 17, + messageId: 'voidReturnInheritedMethod', + }, + { + line: 18, + messageId: 'voidReturnInheritedMethod', + }, + ], + }, ], }); From 125a54a1f02567576eff1b5d2170bb5a6ff1b715 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Sat, 9 Nov 2024 14:28:18 +0200 Subject: [PATCH 12/20] test edge case of no static key --- .../src/rules/no-misused-promises.ts | 3 ++- .../tests/rules/no-misused-promises.test.ts | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index 0e5a0120bb52..b209ed7d4d32 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -575,7 +575,8 @@ export default createRule({ node.type !== AST_NODE_TYPES.MethodDefinition && node.type !== AST_NODE_TYPES.TSAbstractMethodDefinition && node.type !== AST_NODE_TYPES.TSMethodSignature && - node.type !== AST_NODE_TYPES.TSPropertySignature + node.type !== AST_NODE_TYPES.TSPropertySignature && + node.type !== AST_NODE_TYPES.PropertyDefinition ) { continue; } diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index 5631b14e2044..cca4f92bb9ac 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -1110,6 +1110,19 @@ const obj: O = { async [Symbol.iterator]() {}, async [staticSymbol]() {}, async ownProperty() {}, +}; + `, + }, + { + code: ` +let a; + +type O = { + [a]: () => Promise; +}; + +const obj: O = { + async [a]() {}, }; `, }, @@ -1206,6 +1219,19 @@ class MySubinterfaceExtendsMyInterface extends MyInterface { async [Symbol.asyncIterator](): Promise; async [staticSymbol](): Promise; async ownProperty(): Promise; +} + `, + }, + { + code: ` +let a; + +interface MyInterface { + [a](): void; +} + +class MySubinterfaceExtendsMyInterface implements MyInterface { + [a]: () => Promise; } `, }, From fa27a025eeb77dd9a10007e7c43a84be9a1f04b3 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Sun, 10 Nov 2024 22:46:26 +0200 Subject: [PATCH 13/20] use a type assertion over unreachable runtime conditional --- .../src/rules/no-misused-promises.ts | 17 ++++++----------- packages/eslint-plugin/src/util/misc.ts | 2 +- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index b209ed7d4d32..6b07d1de1e4b 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -4,6 +4,8 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; +import type { NodeWithKey } from '../util'; + import { createRule, getParserServices, @@ -571,17 +573,10 @@ export default createRule({ continue; } - if ( - node.type !== AST_NODE_TYPES.MethodDefinition && - node.type !== AST_NODE_TYPES.TSAbstractMethodDefinition && - node.type !== AST_NODE_TYPES.TSMethodSignature && - node.type !== AST_NODE_TYPES.TSPropertySignature && - node.type !== AST_NODE_TYPES.PropertyDefinition - ) { - continue; - } - - const staticAccessValue = getStaticMemberAccessValue(node, context); + const staticAccessValue = getStaticMemberAccessValue( + node as NodeWithKey, + context, + ); if (!staticAccessValue) { continue; diff --git a/packages/eslint-plugin/src/util/misc.ts b/packages/eslint-plugin/src/util/misc.ts index 38eb0459bb7b..ffd392cde992 100644 --- a/packages/eslint-plugin/src/util/misc.ts +++ b/packages/eslint-plugin/src/util/misc.ts @@ -233,7 +233,7 @@ function isParenlessArrowFunction( ); } -type NodeWithKey = +export type NodeWithKey = | TSESTree.MemberExpression | TSESTree.MethodDefinition | TSESTree.Property From 13127b662c37056c5ef44b54a2d07bde84e69916 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Thu, 14 Nov 2024 20:33:25 +0200 Subject: [PATCH 14/20] rework tests --- .../tests/rules/no-misused-promises.test.ts | 826 +++++++++++++----- 1 file changed, 604 insertions(+), 222 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index db1bc86d4a97..d42226e2b44e 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -1066,162 +1066,439 @@ declare const useCallback: unknown>( ) => T; useCallback(async () => {}); `, + // assignment with various symbols, matching `() => void` with `() => {}` { - code: noFormat` -const staticSymbol = Symbol.for('static symbol'); + code: ` +type O = { + 1: () => void; +}; +const obj: O = { + 1() {}, +}; + `, + }, + { + code: ` type O = { 1: () => void; - 2: () => void; +}; + +const obj: O = { + [1]() {}, +}; + `, + }, + { + code: noFormat` +type O = { stringLiteral: () => void; - computedStringLiteral: () => void; - [Symbol.iterator]: () => void; - [staticSymbol]: () => void; }; const obj: O = { - 1() {}, - [2]() {}, 'stringLiteral'() {}, +}; + `, + }, + { + code: ` +type O = { + computedStringLiteral: () => void; +}; + +const obj: O = { ['computedStringLiteral']() {}, +}; + `, + }, + { + code: ` +type O = { + [Symbol.iterator]: () => void; +}; + +const obj: O = { [Symbol.iterator]() {}, - [staticSymbol]() {} }; `, }, { - code: noFormat` + code: ` const staticSymbol = Symbol.for('static symbol'); +type O = { + [staticSymbol]: () => void; +}; + +const obj: O = { + [staticSymbol]() {}, +}; + `, + }, + // assignment with various symbols, matching `() => Promise` with `async () => {}` + { + code: ` +type O = { + 1: () => Promise; +}; + +const obj: O = { + async 1() {}, +}; + `, + }, + { + code: ` type O = { 1: () => Promise; - 2: () => Promise; +}; + +const obj: O = { + async [1]() {}, +}; + `, + }, + { + code: noFormat` +type O = { stringLiteral: () => Promise; - computedStringLiteral: () => Promise; - [Symbol.iterator]: () => Promise; - [staticSymbol]: () => Promise; }; const obj: O = { - async 1() {}, - async [2]() {}, async 'stringLiteral'() {}, +}; + `, + }, + { + code: ` +type O = { + computedStringLiteral: () => Promise; +}; + +const obj: O = { async ['computedStringLiteral']() {}, +}; + `, + }, + { + code: ` +type O = { + [Symbol.iterator]: () => Promise; +}; + +const obj: O = { async [Symbol.iterator]() {}, - async [staticSymbol]() {}, - async ownProperty() {}, }; `, }, { code: ` -let a; +const staticSymbol = Symbol.for('static symbol'); type O = { - [a]: () => Promise; + [staticSymbol]: () => Promise; }; const obj: O = { - async [a]() {}, + async [staticSymbol]() {}, }; `, }, + // classes with various symbols, matching `() => void` with `() => {}` { - code: noFormat` -const staticSymbol = Symbol.for('static symbol'); + code: ` +class MyClass { + 1(): void {} +} +class MySubclass extends MyClass { + 1(): void {} +} + `, + }, + { + code: ` class MyClass { 1(): void {} - 2(): void {} +} + +class MySubclass extends MyClass { + [1](): void {} +} + `, + }, + { + code: noFormat` +class MyClass { stringLiteral(): void {} - computedStringLiteral(): void {} - [Symbol.asyncIterator](): void {} - [staticSymbol](): void {} } -class MySubclassExtendsMyClass extends MyClass { - 1(): void {} - [2](): void {} +class MySubclass extends MyClass { 'stringLiteral'(): void {} +} + + `, + }, + { + code: ` +class MyClass { + computedStringLiteral(): void {} +} + +class MySubclass extends MyClass { ['computedStringLiteral'](): void {} - [Symbol.asyncIterator](): void {} - [staticSymbol](): void {} - ownProperty(): void {} } `, }, { - code: noFormat` + code: ` +class MyClass { + [Symbol.iterator](): void {} +} + +class MySubclass extends MyClass { + [Symbol.iterator](): void {} +} + `, + }, + { + code: ` const staticSymbol = Symbol.for('static symbol'); +class MyClass { + [staticSymbol](): void {} +} + +class MySubclass extends MyClass { + [staticSymbol](): void {} +} + `, + }, + // classes with various symbols, matching `() => Promise` with `async () => {}` + { + code: ` +class MyClass { + 1(): Promise {} +} + +class MySubclass extends MyClass { + async 1(): void {} +} + `, + }, + { + code: ` class MyClass { 1(): Promise {} - 2(): Promise {} +} + +class MySubclass extends MyClass { + async [1](): void {} +} + `, + }, + { + code: noFormat` +class MyClass { stringLiteral(): Promise {} +} + +class MySubclass extends MyClass { + async 'stringLiteral'(): void {} +} + + `, + }, + { + code: ` +class MyClass { computedStringLiteral(): Promise {} - [Symbol.asyncIterator](): Promise {} - [staticSymbol](): Promise {} } -class MySubclassExtendsMyClass extends MyClass { - async 1(): Promise {} - async [2](): Promise {} - async 'stringLiteral'(): Promise {} - async ['computedStringLiteral'](): Promise {} - async [Symbol.asyncIterator](): Promise {} - async [staticSymbol](): Promise {} - async ownProperty(): Promise {} +class MySubclass extends MyClass { + async ['computedStringLiteral'](): void {} } `, }, { - code: noFormat` + code: ` +class MyClass { + [Symbol.iterator](): Promise {} +} + +class MySubclass extends MyClass { + async [Symbol.iterator](): void {} +} + `, + }, + { + code: ` const staticSymbol = Symbol.for('static symbol'); +class MyClass { + [staticSymbol](): Promise {} +} + +class MySubclass extends MyClass { + async [staticSymbol](): void {} +} + `, + }, + // interfaces with various symbols, matching `() => void` with `() => {}` + { + code: ` interface MyInterface { 1(): void; - 2(): void; +} + +class MySubclass extends MyInterface { + 1(): void {} +} + `, + }, + { + code: ` +interface MyInterface { + 1(): void; +} + +class MySubclass extends MyInterface { + [1](): void {} +} + `, + }, + { + code: noFormat` +interface MyInterface { stringLiteral(): void; +} + +class MySubclass extends MyInterface { + 'stringLiteral'(): void {} +} + + `, + }, + { + code: ` +interface MyInterface { computedStringLiteral(): void; - [Symbol.asyncIterator](): void; - [staticSymbol](): void; } -class MySubinterfaceExtendsMyInterface extends MyInterface { - async 1(): void; - async [2](): void; - async 'stringLiteral'(): void; - async ['computedStringLiteral'](): void; - async [Symbol.asyncIterator](): void; - async [staticSymbol](): void; - async ownProperty(): void; +class MySubclass extends MyInterface { + ['computedStringLiteral'](): void {} } `, }, { - code: noFormat` + code: ` +interface MyInterface { + [Symbol.iterator](): void; +} + +class MySubclass extends MyInterface { + [Symbol.iterator](): void {} +} + `, + }, + { + code: ` const staticSymbol = Symbol.for('static symbol'); +interface MyInterface { + [staticSymbol](): void; +} + +class MySubclass extends MyInterface { + [staticSymbol](): void {} +} + `, + }, + + // classes with various symbols, matching `() => Promise` with `async () => {}` + { + code: ` +interface MyInterface { + 1(): Promise; +} + +class MySubclass extends MyInterface { + async 1(): void {} +} + `, + }, + { + code: ` interface MyInterface { 1(): Promise; - 2(): Promise; +} + +class MySubclass extends MyInterface { + async [1](): void {} +} + `, + }, + { + code: noFormat` +interface MyInterface { stringLiteral(): Promise; +} + +class MySubclass extends MyInterface { + async 'stringLiteral'(): void {} +} + + `, + }, + { + code: ` +interface MyInterface { computedStringLiteral(): Promise; - [Symbol.asyncIterator](): Promise; +} + +class MySubclass extends MyInterface { + async ['computedStringLiteral'](): void {} +} + `, + }, + { + code: ` +interface MyInterface { + [Symbol.iterator](): Promise; +} + +class MySubclass extends MyInterface { + async [Symbol.iterator](): void {} +} + `, + }, + { + code: ` +const staticSymbol = Symbol.for('static symbol'); + +interface MyInterface { [staticSymbol](): Promise; } -class MySubinterfaceExtendsMyInterface extends MyInterface { - async 1(): Promise; - async [2](): Promise; - async 'stringLiteral'(): Promise; - async ['computedStringLiteral'](): Promise; - async [Symbol.asyncIterator](): Promise; - async [staticSymbol](): Promise; - async ownProperty(): Promise; +class MySubclass extends MyInterface { + async [staticSymbol](): void {} } `, }, + // `undefined` symbol + { + code: ` +let a; + +type O = { + [a]: () => Promise; +}; + +const obj: O = { + async [a]() {}, +}; + `, + }, { code: ` let a; @@ -2660,51 +2937,138 @@ const o: HasVoidMethod = { `, errors: [ { - column: 14, - endColumn: 29, - endLine: 7, - line: 7, + column: 14, + endColumn: 29, + endLine: 7, + line: 7, + messageId: 'voidReturnProperty', + }, + ], + }, + { + code: ` +type HasVoidMethod = { + f(): void; +}; +const obj: HasVoidMethod = { + f() { + return Promise.resolve('foo'); + }, +}; + `, + errors: [ + { + column: 3, + endColumn: 4, + endLine: 6, + line: 6, + messageId: 'voidReturnProperty', + }, + ], + }, + { + code: ` +type HasVoidMethod = { + f(): void; +}; +const obj: HasVoidMethod = { + f(): Promise { + throw new Error(); + }, +}; + `, + errors: [ + { + column: 8, + endColumn: 21, + endLine: 6, + line: 6, + messageId: 'voidReturnProperty', + }, + ], + }, + { + code: ` +type O = { f: () => void }; +const asyncFunction = async () => 'foo'; +const obj: O = { + f: asyncFunction, +}; + `, + errors: [ + { + column: 6, + endColumn: 19, + endLine: 5, + line: 5, + messageId: 'voidReturnProperty', + }, + ], + }, + { + code: ` +type O = { f: () => void }; +const obj: O = { + f: async (): Promise => 'foo', +}; + `, + errors: [ + { + column: 16, + endColumn: 31, + endLine: 4, + line: 4, + messageId: 'voidReturnProperty', + }, + ], + }, + // assignment with various symbols, matching `() => void` with `async () => {}` + { + code: ` +type O = { + 1: () => void; +}; + +const obj: O = { + async 1() {}, +}; + `, + errors: [ + { + line: 6, messageId: 'voidReturnProperty', }, ], }, { code: ` -type HasVoidMethod = { - f(): void; +type O = { + 1: () => void; }; -const obj: HasVoidMethod = { - f() { - return Promise.resolve('foo'); - }, + +const obj: O = { + async [1]() {}, }; `, errors: [ { - column: 3, - endColumn: 4, - endLine: 6, line: 6, messageId: 'voidReturnProperty', }, ], }, { - code: ` -type HasVoidMethod = { - f(): void; + code: noFormat` +type O = { + stringLiteral: () => void; }; -const obj: HasVoidMethod = { - f(): Promise { - throw new Error(); - }, + +const obj: O = { + async 'stringLiteral'() {}, }; `, errors: [ { - column: 8, - endColumn: 21, - endLine: 6, line: 6, messageId: 'voidReturnProperty', }, @@ -2712,208 +3076,226 @@ const obj: HasVoidMethod = { }, { code: ` -type O = { f: () => void }; -const asyncFunction = async () => 'foo'; +type O = { + computedStringLiteral: () => void; +}; + const obj: O = { - f: asyncFunction, + async ['computedStringLiteral']() {}, }; `, errors: [ { - column: 6, - endColumn: 19, - endLine: 5, - line: 5, + line: 6, messageId: 'voidReturnProperty', }, ], }, { code: ` -type O = { f: () => void }; +type O = { + [Symbol.iterator]: () => void; +}; + const obj: O = { - f: async (): Promise => 'foo', + async [Symbol.iterator]() {}, }; `, errors: [ { - column: 16, - endColumn: 31, - endLine: 4, - line: 4, + line: 6, messageId: 'voidReturnProperty', }, ], }, { - code: noFormat` + code: ` const staticSymbol = Symbol.for('static symbol'); + type O = { - 1: () => void; - 2: () => void; - stringLiteral: () => void; - computedStringLiteral: () => void; - [Symbol.iterator]: () => void; [staticSymbol]: () => void; }; + const obj: O = { - async 1() { - return 0; - }, - async [2]() { - return 0; - }, - async 'stringLiteral'() { - return 0; - }, - async ['computedStringLiteral']() { - return 0; - }, - async [Symbol.iterator]() { - return 0; - }, - async [staticSymbol]() { - return 0; - }, - async ownProperty() { - return 0; - } + async [staticSymbol]() {}, }; `, errors: [ { - line: 14, + line: 6, messageId: 'voidReturnProperty', }, + ], + }, + // classes with various symbols, matching `() => void` with `async () => {}` + { + code: ` +class MyClass { + 1(): void {} +} + +class MySubclass extends MyClass { + async 1(): Promise {} +} + `, + errors: [ { - line: 17, + line: 6, messageId: 'voidReturnProperty', }, + ], + }, + { + code: ` +class MyClass { + 1(): void {} +} + +class MySubclass extends MyClass { + async [1](): Promise {} +} + `, + errors: [ { - line: 20, + line: 6, messageId: 'voidReturnProperty', }, + ], + }, + { + code: noFormat` +class MyClass { + stringLiteral(): void {} +} + +class MySubclass extends MyClass { + async 'stringLiteral'(): Promise {} +} + `, + errors: [ { - line: 23, + line: 6, messageId: 'voidReturnProperty', }, + ], + }, + { + code: ` +class MyClass { + computedStringLiteral(): void {} +} + +class MySubclass extends MyClass { + async ['computedStringLiteral'](): Promise {} +} + `, + errors: [ { - line: 26, + line: 6, messageId: 'voidReturnProperty', }, ], }, { - code: noFormat` -const staticSymbol = Symbol.for('static symbol'); + code: ` class MyClass { - 1(): void { - return; - } - 2(): void { - return; - } - stringLiteral(): void { - return; - } - computedStringLiteral(): void { - return; - } - [Symbol.asyncIterator](): void { - return; - } - [staticSymbol](): void { - return; - } + [Symbol.asyncIterator](): void {} } -class MySubclassExtendsMyClass extends MyClass { - async 1(): Promise { - await Promise.resolve(); - } - async [2](): Promise { - await Promise.resolve(); - } - async 'stringLiteral'(): Promise { - await Promise.resolve(); - } - async ['computedStringLiteral'](): Promise { - await Promise.resolve(); - } - async [Symbol.asyncIterator](): Promise { - await Promise.resolve(); - } - async [staticSymbol](): Promise { - await Promise.resolve(); - } - async ownProperty(): Promise { - await Promise.resolve(); - } + +class MySubclass extends MyClass { + async [Symbol.asyncIterator](): Promise {} } `, errors: [ { - line: 26, - messageId: 'voidReturnInheritedMethod', - }, - { - line: 29, - messageId: 'voidReturnInheritedMethod', - }, - { - line: 32, - messageId: 'voidReturnInheritedMethod', - }, - { - line: 35, - messageId: 'voidReturnInheritedMethod', - }, - { - line: 38, - messageId: 'voidReturnInheritedMethod', + line: 6, + messageId: 'voidReturnProperty', }, ], }, + // interfaces with various symbols, matching `() => void` with `() => Promise` { - code: noFormat` -const staticSymbol = Symbol.for('static symbol'); + code: ` interface MyInterface { - 1(): void - 2(): void - stringLiteral(): void - computedStringLiteral(): void - [Symbol.asyncIterator](): void - [staticSymbol](): void + 1(): void; } -interface MySubinterfaceExtendsMyInterface extends MyInterface { - 1(): Promise - [2](): Promise - 'stringLiteral'(): Promise - ['computedStringLiteral'](): Promise - [Symbol.asyncIterator](): Promise - [staticSymbol](): Promise - ownProperty(): Promise + +interface MySubinterface extends MyInterface { + 1(): Promise; } `, errors: [ { - line: 14, - messageId: 'voidReturnInheritedMethod', + line: 6, + messageId: 'voidReturnProperty', }, + ], + }, + { + code: ` +interface MyInterface { + 1(): void; +} + +interface MySubinterface extends MyInterface { + [1](): Promise; +} + `, + errors: [ { - line: 15, - messageId: 'voidReturnInheritedMethod', + line: 6, + messageId: 'voidReturnProperty', }, + ], + }, + { + code: ` +interface MyInterface { + stringLiteral(): void; +} + +interface MySubinterface extends MyInterface { + 'stringLiteral'(): Promise; +} + `, + errors: [ { - line: 16, - messageId: 'voidReturnInheritedMethod', + line: 6, + messageId: 'voidReturnProperty', }, + ], + }, + { + code: ` +interface MyInterface { + computedStringLiteral(): void; +} + +interface MySubinterface extends MyInterface { + ['computedStringLiteral'](): Promise; +} + `, + errors: [ { - line: 17, - messageId: 'voidReturnInheritedMethod', + line: 6, + messageId: 'voidReturnProperty', }, + ], + }, + { + code: ` +interface MyInterface { + [Symbol.asyncIterator](): void; +} + +interface MySubinterface extends MyInterface { + [Symbol.asyncIterator](): Promise; +} + `, + errors: [ { - line: 18, - messageId: 'voidReturnInheritedMethod', + line: 6, + messageId: 'voidReturnProperty', }, ], }, From 800a50268e0e8baaac2af8d27b08a75c1f085f53 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Thu, 26 Dec 2024 22:38:08 +0200 Subject: [PATCH 15/20] adjust tests --- .../tests/rules/no-misused-promises.test.ts | 79 ++++++------------- 1 file changed, 25 insertions(+), 54 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index d42226e2b44e..37840e9386cb 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -1066,7 +1066,6 @@ declare const useCallback: unknown>( ) => T; useCallback(async () => {}); `, - // assignment with various symbols, matching `() => void` with `() => {}` { code: ` type O = { @@ -1135,7 +1134,6 @@ const obj: O = { }; `, }, - // assignment with various symbols, matching `() => Promise` with `async () => {}` { code: ` type O = { @@ -1204,7 +1202,6 @@ const obj: O = { }; `, }, - // classes with various symbols, matching `() => void` with `() => {}` { code: ` class MyClass { @@ -1274,7 +1271,6 @@ class MySubclass extends MyClass { } `, }, - // classes with various symbols, matching `() => Promise` with `async () => {}` { code: ` class MyClass { @@ -1344,7 +1340,6 @@ class MySubclass extends MyClass { } `, }, - // interfaces with various symbols, matching `() => void` with `() => {}` { code: ` interface MyInterface { @@ -1415,7 +1410,6 @@ class MySubclass extends MyInterface { `, }, - // classes with various symbols, matching `() => Promise` with `async () => {}` { code: ` interface MyInterface { @@ -1485,7 +1479,6 @@ class MySubclass extends MyInterface { } `, }, - // `undefined` symbol { code: ` let a; @@ -3022,7 +3015,6 @@ const obj: O = { }, ], }, - // assignment with various symbols, matching `() => void` with `async () => {}` { code: ` type O = { @@ -3035,7 +3027,7 @@ const obj: O = { `, errors: [ { - line: 6, + line: 7, messageId: 'voidReturnProperty', }, ], @@ -3052,7 +3044,7 @@ const obj: O = { `, errors: [ { - line: 6, + line: 7, messageId: 'voidReturnProperty', }, ], @@ -3069,7 +3061,7 @@ const obj: O = { `, errors: [ { - line: 6, + line: 7, messageId: 'voidReturnProperty', }, ], @@ -3086,7 +3078,7 @@ const obj: O = { `, errors: [ { - line: 6, + line: 7, messageId: 'voidReturnProperty', }, ], @@ -3103,31 +3095,11 @@ const obj: O = { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', - }, - ], - }, - { - code: ` -const staticSymbol = Symbol.for('static symbol'); - -type O = { - [staticSymbol]: () => void; -}; - -const obj: O = { - async [staticSymbol]() {}, -}; - `, - errors: [ - { - line: 6, + line: 7, messageId: 'voidReturnProperty', }, ], }, - // classes with various symbols, matching `() => void` with `async () => {}` { code: ` class MyClass { @@ -3140,8 +3112,8 @@ class MySubclass extends MyClass { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', + line: 7, + messageId: 'voidReturnInheritedMethod', }, ], }, @@ -3157,8 +3129,8 @@ class MySubclass extends MyClass { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', + line: 7, + messageId: 'voidReturnInheritedMethod', }, ], }, @@ -3174,8 +3146,8 @@ class MySubclass extends MyClass { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', + line: 7, + messageId: 'voidReturnInheritedMethod', }, ], }, @@ -3191,8 +3163,8 @@ class MySubclass extends MyClass { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', + line: 7, + messageId: 'voidReturnInheritedMethod', }, ], }, @@ -3208,12 +3180,11 @@ class MySubclass extends MyClass { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', + line: 7, + messageId: 'voidReturnInheritedMethod', }, ], }, - // interfaces with various symbols, matching `() => void` with `() => Promise` { code: ` interface MyInterface { @@ -3226,8 +3197,8 @@ interface MySubinterface extends MyInterface { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', + line: 7, + messageId: 'voidReturnInheritedMethod', }, ], }, @@ -3243,8 +3214,8 @@ interface MySubinterface extends MyInterface { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', + line: 7, + messageId: 'voidReturnInheritedMethod', }, ], }, @@ -3260,8 +3231,8 @@ interface MySubinterface extends MyInterface { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', + line: 7, + messageId: 'voidReturnInheritedMethod', }, ], }, @@ -3277,8 +3248,8 @@ interface MySubinterface extends MyInterface { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', + line: 7, + messageId: 'voidReturnInheritedMethod', }, ], }, @@ -3294,8 +3265,8 @@ interface MySubinterface extends MyInterface { `, errors: [ { - line: 6, - messageId: 'voidReturnProperty', + line: 7, + messageId: 'voidReturnInheritedMethod', }, ], }, From a3d3fb3cab7938020bed341ff2f3628393a84304 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Thu, 26 Dec 2024 22:43:58 +0200 Subject: [PATCH 16/20] don't hard-code solution for well known symbols --- packages/eslint-plugin/src/rules/no-misused-promises.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index 47323b14f565..d6357439f8de 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -989,11 +989,10 @@ function getHeritageTypes( } function getWellKnownStringOfSymbol(symbol: symbol): string | null { - switch (symbol) { - case Symbol.iterator: - return 'iterator'; - case Symbol.asyncIterator: - return 'asyncIterator'; + const description = symbol.description; + + if (description?.startsWith('Symbol.')) { + return description.replace(/^Symbol./, ''); } return null; From cffb24a323e9781713794fe2a081bac9bd1d6d03 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Thu, 26 Dec 2024 23:03:32 +0200 Subject: [PATCH 17/20] codecov --- .../eslint-plugin/src/rules/no-misused-promises.ts | 6 ++++-- .../tests/rules/no-misused-promises.test.ts | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index d6357439f8de..20ec612af961 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -989,9 +989,11 @@ function getHeritageTypes( } function getWellKnownStringOfSymbol(symbol: symbol): string | null { - const description = symbol.description; + // symbol with no description is returned as `undefined` by `getStaticMemberAccessValue` + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const description = symbol.description!; - if (description?.startsWith('Symbol.')) { + if (description.startsWith('Symbol.')) { return description.replace(/^Symbol./, ''); } diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index 37840e9386cb..e427832b37c3 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -1502,6 +1502,19 @@ interface MyInterface { class MySubinterfaceExtendsMyInterface implements MyInterface { [a]: () => Promise; +} + `, + }, + { + code: ` +const staticSymbol = Symbol(); + +interface MyInterface { + [staticSymbol](): Promise; +} + +class MySubclass extends MyInterface { + async [staticSymbol](): void {} } `, }, From 528f5c7038c6c3fd89379c7757af8c58aca76c1f Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Thu, 26 Dec 2024 23:16:49 +0200 Subject: [PATCH 18/20] remove redundant tests and fix type errors on tests --- .../tests/rules/no-misused-promises.test.ts | 155 +----------------- 1 file changed, 8 insertions(+), 147 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index e427832b37c3..7579a46c57cc 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -1273,80 +1273,11 @@ class MySubclass extends MyClass { }, { code: ` -class MyClass { - 1(): Promise {} -} - -class MySubclass extends MyClass { - async 1(): void {} -} - `, - }, - { - code: ` -class MyClass { - 1(): Promise {} -} - -class MySubclass extends MyClass { - async [1](): void {} -} - `, - }, - { - code: noFormat` -class MyClass { - stringLiteral(): Promise {} -} - -class MySubclass extends MyClass { - async 'stringLiteral'(): void {} -} - - `, - }, - { - code: ` -class MyClass { - computedStringLiteral(): Promise {} -} - -class MySubclass extends MyClass { - async ['computedStringLiteral'](): void {} -} - `, - }, - { - code: ` -class MyClass { - [Symbol.iterator](): Promise {} -} - -class MySubclass extends MyClass { - async [Symbol.iterator](): void {} -} - `, - }, - { - code: ` -const staticSymbol = Symbol.for('static symbol'); - -class MyClass { - [staticSymbol](): Promise {} -} - -class MySubclass extends MyClass { - async [staticSymbol](): void {} -} - `, - }, - { - code: ` interface MyInterface { 1(): void; } -class MySubclass extends MyInterface { +class MySubclass implements MyInterface { 1(): void {} } `, @@ -1357,7 +1288,7 @@ interface MyInterface { 1(): void; } -class MySubclass extends MyInterface { +class MySubclass implements MyInterface { [1](): void {} } `, @@ -1368,7 +1299,7 @@ interface MyInterface { stringLiteral(): void; } -class MySubclass extends MyInterface { +class MySubclass implements MyInterface { 'stringLiteral'(): void {} } @@ -1380,7 +1311,7 @@ interface MyInterface { computedStringLiteral(): void; } -class MySubclass extends MyInterface { +class MySubclass implements MyInterface { ['computedStringLiteral'](): void {} } `, @@ -1391,7 +1322,7 @@ interface MyInterface { [Symbol.iterator](): void; } -class MySubclass extends MyInterface { +class MySubclass implements MyInterface { [Symbol.iterator](): void {} } `, @@ -1404,81 +1335,11 @@ interface MyInterface { [staticSymbol](): void; } -class MySubclass extends MyInterface { +class MySubclass implements MyInterface { [staticSymbol](): void {} } `, }, - - { - code: ` -interface MyInterface { - 1(): Promise; -} - -class MySubclass extends MyInterface { - async 1(): void {} -} - `, - }, - { - code: ` -interface MyInterface { - 1(): Promise; -} - -class MySubclass extends MyInterface { - async [1](): void {} -} - `, - }, - { - code: noFormat` -interface MyInterface { - stringLiteral(): Promise; -} - -class MySubclass extends MyInterface { - async 'stringLiteral'(): void {} -} - - `, - }, - { - code: ` -interface MyInterface { - computedStringLiteral(): Promise; -} - -class MySubclass extends MyInterface { - async ['computedStringLiteral'](): void {} -} - `, - }, - { - code: ` -interface MyInterface { - [Symbol.iterator](): Promise; -} - -class MySubclass extends MyInterface { - async [Symbol.iterator](): void {} -} - `, - }, - { - code: ` -const staticSymbol = Symbol.for('static symbol'); - -interface MyInterface { - [staticSymbol](): Promise; -} - -class MySubclass extends MyInterface { - async [staticSymbol](): void {} -} - `, - }, { code: ` let a; @@ -1513,8 +1374,8 @@ interface MyInterface { [staticSymbol](): Promise; } -class MySubclass extends MyInterface { - async [staticSymbol](): void {} +class MySubclass implements MyInterface { + async [staticSymbol](): Promise {} } `, }, From 75f8b6562535391a343bfcbb5a43b0af1d4023ca Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Thu, 26 Dec 2024 23:30:37 +0200 Subject: [PATCH 19/20] refactor --- .../eslint-plugin/src/rules/no-misused-promises.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index 20ec612af961..4f8c64b1b0c3 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -989,12 +989,12 @@ function getHeritageTypes( } function getWellKnownStringOfSymbol(symbol: symbol): string | null { - // symbol with no description is returned as `undefined` by `getStaticMemberAccessValue` - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const description = symbol.description!; + const globalSymbolKeys = Object.getOwnPropertyNames(Symbol); - if (description.startsWith('Symbol.')) { - return description.replace(/^Symbol./, ''); + for (const key of globalSymbolKeys) { + if (symbol === Symbol[key as keyof typeof Symbol]) { + return key; + } } return null; From 6c48db98ca870954b929916cb9d463b82b610278 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Mon, 30 Dec 2024 20:46:16 +0200 Subject: [PATCH 20/20] don't skip empty strings --- .../src/rules/no-misused-promises.ts | 6 +++--- .../tests/rules/no-misused-promises.test.ts | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index 4f8c64b1b0c3..d48bc0d3d428 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -493,7 +493,7 @@ export default createRule({ return; } const staticAccessValue = getStaticMemberAccessValue(node, context); - if (!staticAccessValue) { + if (staticAccessValue == null) { return; } const propertySymbol = getMemberIfExists( @@ -604,7 +604,7 @@ export default createRule({ context, ); - if (!staticAccessValue) { + if (staticAccessValue == null) { continue; } @@ -1018,7 +1018,7 @@ function getMemberIfExists( const wellKnownSymbolName = getWellKnownStringOfSymbol(staticAccessValue); - if (wellKnownSymbolName) { + if (wellKnownSymbolName != null) { return tsutils.getWellKnownSymbolPropertyOfType( type, wellKnownSymbolName, diff --git a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts index 7579a46c57cc..56824c676ab7 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-promises.test.ts @@ -3135,6 +3135,23 @@ interface MyInterface { interface MySubinterface extends MyInterface { [Symbol.asyncIterator](): Promise; +} + `, + errors: [ + { + line: 7, + messageId: 'voidReturnInheritedMethod', + }, + ], + }, + { + code: ` +class MyClass { + ''(): void {} +} + +class MySubclass extends MyClass { + async ''(): Promise {} } `, errors: [