diff --git a/packages/eslint-plugin/src/rules/class-literal-property-style.ts b/packages/eslint-plugin/src/rules/class-literal-property-style.ts index 28d4a5cc78ba..9f02142f4d6e 100644 --- a/packages/eslint-plugin/src/rules/class-literal-property-style.ts +++ b/packages/eslint-plugin/src/rules/class-literal-property-style.ts @@ -4,7 +4,6 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import { createRule, getStaticMemberAccessValue, - getStaticStringValue, isAssignee, isFunction, isStaticMemberAccessOfValue, @@ -25,7 +24,7 @@ interface NodeWithModifiers { interface PropertiesInfo { properties: TSESTree.PropertyDefinition[]; - excludeSet: Set; + excludeSet: Set; } const printNodeModifiers = ( @@ -132,9 +131,7 @@ export default createRule({ const { excludeSet } = propertiesInfoStack[propertiesInfoStack.length - 1]; - const name = - getStaticStringValue(node.property) ?? - context.sourceCode.getText(node.property); + const name = getStaticMemberAccessValue(node, context); if (name) { excludeSet.add(name); diff --git a/packages/eslint-plugin/src/rules/class-methods-use-this.ts b/packages/eslint-plugin/src/rules/class-methods-use-this.ts index 6e27a6229f12..4b369d7a51be 100644 --- a/packages/eslint-plugin/src/rules/class-methods-use-this.ts +++ b/packages/eslint-plugin/src/rules/class-methods-use-this.ts @@ -184,7 +184,9 @@ export default createRule({ node.key.type === AST_NODE_TYPES.PrivateIdentifier ? '#' : ''; const name = getStaticMemberAccessValue(node, context); - return !exceptMethods.has(hashIfNeeded + (name ?? '')); + return ( + typeof name !== 'string' || !exceptMethods.has(hashIfNeeded + name) + ); } /** diff --git a/packages/eslint-plugin/src/util/isArrayMethodCallWithPredicate.ts b/packages/eslint-plugin/src/util/isArrayMethodCallWithPredicate.ts index 746e9003722c..39e46d9dda39 100644 --- a/packages/eslint-plugin/src/util/isArrayMethodCallWithPredicate.ts +++ b/packages/eslint-plugin/src/util/isArrayMethodCallWithPredicate.ts @@ -9,7 +9,7 @@ import * as tsutils from 'ts-api-utils'; import { getStaticMemberAccessValue } from './misc'; -const ARRAY_PREDICATE_FUNCTIONS = new Set([ +const ARRAY_PREDICATE_FUNCTIONS = new Set([ 'filter', 'find', 'findIndex', @@ -30,7 +30,7 @@ export function isArrayMethodCallWithPredicate( const staticAccessValue = getStaticMemberAccessValue(node.callee, context); - if (!staticAccessValue || !ARRAY_PREDICATE_FUNCTIONS.has(staticAccessValue)) { + if (!ARRAY_PREDICATE_FUNCTIONS.has(staticAccessValue)) { return false; } diff --git a/packages/eslint-plugin/src/util/misc.ts b/packages/eslint-plugin/src/util/misc.ts index aeed9f96d039..41933dc551c2 100644 --- a/packages/eslint-plugin/src/util/misc.ts +++ b/packages/eslint-plugin/src/util/misc.ts @@ -239,36 +239,85 @@ type NodeWithKey = | TSESTree.PropertyDefinition | TSESTree.TSAbstractMethodDefinition | TSESTree.TSAbstractPropertyDefinition; + +/** + * Gets a member being accessed or declared if its value can be determined statically, and + * resolves it to the string or symbol value that will be used as the actual member + * access key at runtime. Otherwise, returns `undefined`. + * + * ```ts + * x.member // returns 'member' + * ^^^^^^^^ + * + * x?.member // returns 'member' (optional chaining is treated the same) + * ^^^^^^^^^ + * + * x['value'] // returns 'value' + * ^^^^^^^^^^ + * + * x[Math.random()] // returns undefined (not a static value) + * ^^^^^^^^^^^^^^^^ + * + * arr[0] // returns '0' (NOT 0) + * ^^^^^^ + * + * arr[0n] // returns '0' (NOT 0n) + * ^^^^^^^ + * + * const s = Symbol.for('symbolName') + * x[s] // returns `Symbol.for('symbolName')` (since it's a static/global symbol) + * ^^^^ + * + * const us = Symbol('symbolName') + * x[us] // returns undefined (since it's a unique symbol, so not statically analyzable) + * ^^^^^ + * + * var object = { + * 1234: '4567', // returns '1234' (NOT 1234) + * ^^^^^^^^^^^^ + * method() { } // returns 'method' + * ^^^^^^^^^^^^ + * } + * + * class WithMembers { + * foo: string // returns 'foo' + * ^^^^^^^^^^^ + * } + * ``` + */ function getStaticMemberAccessValue( node: NodeWithKey, { sourceCode }: RuleContext, -): string | undefined { +): string | symbol | undefined { const key = node.type === AST_NODE_TYPES.MemberExpression ? node.property : node.key; - if (!node.computed) { - return key.type === AST_NODE_TYPES.Literal - ? `${key.value}` - : (key as TSESTree.Identifier | TSESTree.PrivateIdentifier).name; + const { type } = key; + if ( + !node.computed && + (type === AST_NODE_TYPES.Identifier || + type === AST_NODE_TYPES.PrivateIdentifier) + ) { + return key.name; + } + const result = getStaticValue(key, sourceCode.getScope(node)); + if (!result) { + return undefined; } - const value = getStaticValue(key, sourceCode.getScope(node))?.value as - | string - | number - | null - | undefined; - return value == null ? undefined : `${value}`; + const { value } = result; + return typeof value === 'symbol' ? value : String(value); } /** * Answers whether the member expression looks like - * `x.memberName`, `x['memberName']`, - * or even `const mn = 'memberName'; x[mn]` (or optional variants thereof). + * `x.value`, `x['value']`, + * or even `const v = 'value'; x[v]` (or optional variants thereof). */ const isStaticMemberAccessOfValue = ( memberExpression: NodeWithKey, context: RuleContext, - ...values: string[] + ...values: (string | symbol)[] ): boolean => - (values as (string | undefined)[]).includes( + (values as (string | symbol | undefined)[]).includes( getStaticMemberAccessValue(memberExpression, context), ); diff --git a/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts b/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts index eda213576ff8..3bff869ae8b1 100644 --- a/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts @@ -407,6 +407,7 @@ export class Test { 'method'() {} ['prop']() {} [\`prop\`]() {} + [null]() {} [\`\${v}\`](): void {} foo = () => { @@ -416,7 +417,7 @@ export class Test { `, options: [ { - allowedNames: ['prop', 'method', 'foo'], + allowedNames: ['prop', 'method', 'null', 'foo'], }, ], }, diff --git a/packages/eslint-plugin/tests/rules/prefer-promise-reject-errors.test.ts b/packages/eslint-plugin/tests/rules/prefer-promise-reject-errors.test.ts index d890886eff15..e78575881255 100644 --- a/packages/eslint-plugin/tests/rules/prefer-promise-reject-errors.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-promise-reject-errors.test.ts @@ -266,6 +266,15 @@ ruleTester.run('prefer-promise-reject-errors', rule, { declare const foo: PromiseConstructor; foo.reject(new Error()); `, + 'console[Symbol.iterator]();', + ` + class A { + a = []; + [Symbol.iterator]() { + return this.a[Symbol.iterator](); + } + } + `, ], invalid: [ { 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