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: [ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy