diff --git a/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts b/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts index f17a19f1f6d..c8fb885a73e 100644 --- a/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts @@ -222,6 +222,21 @@ ruleTester.run('prefer-readonly-parameter-types', rule, { }, ], }, + // PrivateIdentifier is handled without throwing error. + { + code: ` + class Foo { + readonly #privateField = 'foo'; + #privateMember() {} + } + function foo(arg: Foo) {} + `, + options: [ + { + treatMethodsAsReadonly: true, + }, + ], + }, // parameter properties should work fine { diff --git a/packages/type-utils/src/propertyTypes.ts b/packages/type-utils/src/propertyTypes.ts index 5e2f1054239..09e04b9049d 100644 --- a/packages/type-utils/src/propertyTypes.ts +++ b/packages/type-utils/src/propertyTypes.ts @@ -7,7 +7,7 @@ export function getTypeOfPropertyOfName( escapedName?: ts.__String, ): ts.Type | undefined { // Most names are directly usable in the checker and aren't different from escaped names - if (!escapedName || !name.startsWith('__')) { + if (!escapedName || !isSymbol(escapedName)) { return checker.getTypeOfPropertyOfType(type, name); } @@ -34,3 +34,18 @@ export function getTypeOfPropertyOfType( property.getEscapedName(), ); } + +// Symbolic names need to be specially handled because TS api is not sufficient for these cases. +function isSymbol(escapedName: string): boolean { + return isKnownSymbol(escapedName) || isPrivateIdentifierSymbol(escapedName); +} + +// case for escapedName: "__@foo@10", name: "__@foo@10" +function isKnownSymbol(escapedName: string): boolean { + return escapedName.startsWith('__@'); +} + +// case for escapedName: "__#1@#foo", name: "#foo" +function isPrivateIdentifierSymbol(escapedName: string): boolean { + return escapedName.startsWith('__#'); +}