From 6f43b64c84ca7cab17f79f8d8e285fa48ba250e6 Mon Sep 17 00:00:00 2001 From: umeshmore45 Date: Sun, 8 Mar 2026 15:50:10 +0530 Subject: [PATCH 1/2] fix(declaration-emit): suppress TS4055/TS4073 for protected methods using typeof parameter --- .../transformers/declarations/diagnostics.ts | 9 ++- .../protectedMethodTypeofParameter.js | 45 ++++++++++++ .../protectedMethodTypeofParameter.symbols | 57 ++++++++++++++++ .../protectedMethodTypeofParameter.types | 68 +++++++++++++++++++ .../protectedMethodTypeofParameter.ts | 22 ++++++ 5 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/protectedMethodTypeofParameter.js create mode 100644 tests/baselines/reference/protectedMethodTypeofParameter.symbols create mode 100644 tests/baselines/reference/protectedMethodTypeofParameter.types create mode 100644 tests/cases/compiler/protectedMethodTypeofParameter.ts diff --git a/src/compiler/transformers/declarations/diagnostics.ts b/src/compiler/transformers/declarations/diagnostics.ts index 873f23cbf7987..f9aa4ff0d4d46 100644 --- a/src/compiler/transformers/declarations/diagnostics.ts +++ b/src/compiler/transformers/declarations/diagnostics.ts @@ -31,6 +31,7 @@ import { getAllAccessorDeclarations, getNameOfDeclaration, getTextOfNode, + hasEffectiveModifier, hasSyntacticModifier, ImportEqualsDeclaration, IndexSignatureDeclaration, @@ -220,6 +221,9 @@ export function createGetSymbolAccessibilityDiagnosticForNodeName(node: Declarat Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_private_name_1; } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { + if (hasEffectiveModifier(node, ModifierFlags.Protected)) { + return undefined; + } return symbolAccessibilityResult.errorModuleName ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : @@ -353,7 +357,7 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD }; } - function getReturnTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { + function getReturnTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined { let diagnosticMessage: DiagnosticMessage; switch (node.kind) { case SyntaxKind.ConstructSignature: @@ -387,6 +391,9 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0; } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { + if (hasEffectiveModifier(node, ModifierFlags.Protected)) { + return undefined; + } diagnosticMessage = symbolAccessibilityResult.errorModuleName ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : diff --git a/tests/baselines/reference/protectedMethodTypeofParameter.js b/tests/baselines/reference/protectedMethodTypeofParameter.js new file mode 100644 index 0000000000000..713de599e49c2 --- /dev/null +++ b/tests/baselines/reference/protectedMethodTypeofParameter.js @@ -0,0 +1,45 @@ +//// [tests/cases/compiler/protectedMethodTypeofParameter.ts] //// + +//// [protectedMethodTypeofParameter.ts] +export interface Properties { + propertyA: number; + propertyB: string; +} + +export class A { + public getPropertyValue_Ok( + properties: Properties, + propertyName: keyof Properties, + ): Properties[typeof propertyName] { + return properties[propertyName]; + } + + protected getPropertyValue_Error( + properties: Properties, + propertyName: keyof Properties, + ): Properties[typeof propertyName] { + return properties[propertyName]; + } +} + + +//// [protectedMethodTypeofParameter.js] +export class A { + getPropertyValue_Ok(properties, propertyName) { + return properties[propertyName]; + } + getPropertyValue_Error(properties, propertyName) { + return properties[propertyName]; + } +} + + +//// [protectedMethodTypeofParameter.d.ts] +export interface Properties { + propertyA: number; + propertyB: string; +} +export declare class A { + getPropertyValue_Ok(properties: Properties, propertyName: keyof Properties): Properties[typeof propertyName]; + protected getPropertyValue_Error(properties: Properties, propertyName: keyof Properties): Properties[typeof propertyName]; +} diff --git a/tests/baselines/reference/protectedMethodTypeofParameter.symbols b/tests/baselines/reference/protectedMethodTypeofParameter.symbols new file mode 100644 index 0000000000000..391e783f1597f --- /dev/null +++ b/tests/baselines/reference/protectedMethodTypeofParameter.symbols @@ -0,0 +1,57 @@ +//// [tests/cases/compiler/protectedMethodTypeofParameter.ts] //// + +=== protectedMethodTypeofParameter.ts === +export interface Properties { +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.ts, 0, 0)) + + propertyA: number; +>propertyA : Symbol(Properties.propertyA, Decl(protectedMethodTypeofParameter.ts, 0, 29)) + + propertyB: string; +>propertyB : Symbol(Properties.propertyB, Decl(protectedMethodTypeofParameter.ts, 1, 20)) +} + +export class A { +>A : Symbol(A, Decl(protectedMethodTypeofParameter.ts, 3, 1)) + + public getPropertyValue_Ok( +>getPropertyValue_Ok : Symbol(A.getPropertyValue_Ok, Decl(protectedMethodTypeofParameter.ts, 5, 16)) + + properties: Properties, +>properties : Symbol(properties, Decl(protectedMethodTypeofParameter.ts, 6, 29)) +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.ts, 0, 0)) + + propertyName: keyof Properties, +>propertyName : Symbol(propertyName, Decl(protectedMethodTypeofParameter.ts, 7, 27)) +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.ts, 0, 0)) + + ): Properties[typeof propertyName] { +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.ts, 0, 0)) +>propertyName : Symbol(propertyName, Decl(protectedMethodTypeofParameter.ts, 7, 27)) + + return properties[propertyName]; +>properties : Symbol(properties, Decl(protectedMethodTypeofParameter.ts, 6, 29)) +>propertyName : Symbol(propertyName, Decl(protectedMethodTypeofParameter.ts, 7, 27)) + } + + protected getPropertyValue_Error( +>getPropertyValue_Error : Symbol(A.getPropertyValue_Error, Decl(protectedMethodTypeofParameter.ts, 11, 3)) + + properties: Properties, +>properties : Symbol(properties, Decl(protectedMethodTypeofParameter.ts, 13, 35)) +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.ts, 0, 0)) + + propertyName: keyof Properties, +>propertyName : Symbol(propertyName, Decl(protectedMethodTypeofParameter.ts, 14, 27)) +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.ts, 0, 0)) + + ): Properties[typeof propertyName] { +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.ts, 0, 0)) +>propertyName : Symbol(propertyName, Decl(protectedMethodTypeofParameter.ts, 14, 27)) + + return properties[propertyName]; +>properties : Symbol(properties, Decl(protectedMethodTypeofParameter.ts, 13, 35)) +>propertyName : Symbol(propertyName, Decl(protectedMethodTypeofParameter.ts, 14, 27)) + } +} + diff --git a/tests/baselines/reference/protectedMethodTypeofParameter.types b/tests/baselines/reference/protectedMethodTypeofParameter.types new file mode 100644 index 0000000000000..563ef66655f79 --- /dev/null +++ b/tests/baselines/reference/protectedMethodTypeofParameter.types @@ -0,0 +1,68 @@ +//// [tests/cases/compiler/protectedMethodTypeofParameter.ts] //// + +=== protectedMethodTypeofParameter.ts === +export interface Properties { + propertyA: number; +>propertyA : number +> : ^^^^^^ + + propertyB: string; +>propertyB : string +> : ^^^^^^ +} + +export class A { +>A : A +> : ^ + + public getPropertyValue_Ok( +>getPropertyValue_Ok : (properties: Properties, propertyName: keyof Properties) => Properties[typeof propertyName] +> : ^ ^^ ^^ ^^ ^^^^^ + + properties: Properties, +>properties : Properties +> : ^^^^^^^^^^ + + propertyName: keyof Properties, +>propertyName : keyof Properties +> : ^^^^^^^^^^^^^^^^ + + ): Properties[typeof propertyName] { +>propertyName : keyof Properties +> : ^^^^^^^^^^^^^^^^ + + return properties[propertyName]; +>properties[propertyName] : string | number +> : ^^^^^^^^^^^^^^^ +>properties : Properties +> : ^^^^^^^^^^ +>propertyName : keyof Properties +> : ^^^^^^^^^^^^^^^^ + } + + protected getPropertyValue_Error( +>getPropertyValue_Error : (properties: Properties, propertyName: keyof Properties) => Properties[typeof propertyName] +> : ^ ^^ ^^ ^^ ^^^^^ + + properties: Properties, +>properties : Properties +> : ^^^^^^^^^^ + + propertyName: keyof Properties, +>propertyName : keyof Properties +> : ^^^^^^^^^^^^^^^^ + + ): Properties[typeof propertyName] { +>propertyName : keyof Properties +> : ^^^^^^^^^^^^^^^^ + + return properties[propertyName]; +>properties[propertyName] : string | number +> : ^^^^^^^^^^^^^^^ +>properties : Properties +> : ^^^^^^^^^^ +>propertyName : keyof Properties +> : ^^^^^^^^^^^^^^^^ + } +} + diff --git a/tests/cases/compiler/protectedMethodTypeofParameter.ts b/tests/cases/compiler/protectedMethodTypeofParameter.ts new file mode 100644 index 0000000000000..463494ff9494e --- /dev/null +++ b/tests/cases/compiler/protectedMethodTypeofParameter.ts @@ -0,0 +1,22 @@ +// @declaration: true + +export interface Properties { + propertyA: number; + propertyB: string; +} + +export class A { + public getPropertyValue_Ok( + properties: Properties, + propertyName: keyof Properties, + ): Properties[typeof propertyName] { + return properties[propertyName]; + } + + protected getPropertyValue_Error( + properties: Properties, + propertyName: keyof Properties, + ): Properties[typeof propertyName] { + return properties[propertyName]; + } +} From c517acb5ac48035d46f08f819bf14b17be120d1d Mon Sep 17 00:00:00 2001 From: umeshmore45 Date: Sun, 8 Mar 2026 17:09:17 +0530 Subject: [PATCH 2/2] fix(checker): treat typeof parameter as accessible in declaration emit --- src/compiler/checker.ts | 5 +++ .../transformers/declarations/diagnostics.ts | 7 ---- .../protectedMethodTypeofParameter.d.symbols | 34 +++++++++++++++++ .../protectedMethodTypeofParameter.d.types | 37 +++++++++++++++++++ .../protectedMethodTypeofParameter.d.ts | 8 ++++ 5 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/protectedMethodTypeofParameter.d.symbols create mode 100644 tests/baselines/reference/protectedMethodTypeofParameter.d.types create mode 100644 tests/cases/compiler/protectedMethodTypeofParameter.d.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0567712f11da3..06c06d1b749e2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6158,6 +6158,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { errorNode: firstIdentifier, }; } + // Parameters are always in scope within their enclosing function; `typeof paramName` in a + // return type annotation is valid regardless of method visibility (public, protected, private). + if (symbol.declarations && every(symbol.declarations, isParameter)) { + return { accessibility: SymbolAccessibility.Accessible }; + } // Verify if the symbol is accessible return hasVisibleDeclarations(symbol, shouldComputeAliasToMakeVisible) || { accessibility: SymbolAccessibility.NotAccessible, diff --git a/src/compiler/transformers/declarations/diagnostics.ts b/src/compiler/transformers/declarations/diagnostics.ts index f9aa4ff0d4d46..1915820bd932f 100644 --- a/src/compiler/transformers/declarations/diagnostics.ts +++ b/src/compiler/transformers/declarations/diagnostics.ts @@ -31,7 +31,6 @@ import { getAllAccessorDeclarations, getNameOfDeclaration, getTextOfNode, - hasEffectiveModifier, hasSyntacticModifier, ImportEqualsDeclaration, IndexSignatureDeclaration, @@ -221,9 +220,6 @@ export function createGetSymbolAccessibilityDiagnosticForNodeName(node: Declarat Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_private_name_1; } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { - if (hasEffectiveModifier(node, ModifierFlags.Protected)) { - return undefined; - } return symbolAccessibilityResult.errorModuleName ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : @@ -391,9 +387,6 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0; } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { - if (hasEffectiveModifier(node, ModifierFlags.Protected)) { - return undefined; - } diagnosticMessage = symbolAccessibilityResult.errorModuleName ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : diff --git a/tests/baselines/reference/protectedMethodTypeofParameter.d.symbols b/tests/baselines/reference/protectedMethodTypeofParameter.d.symbols new file mode 100644 index 0000000000000..d739ff7dbb472 --- /dev/null +++ b/tests/baselines/reference/protectedMethodTypeofParameter.d.symbols @@ -0,0 +1,34 @@ +//// [tests/cases/compiler/protectedMethodTypeofParameter.d.ts] //// + +=== protectedMethodTypeofParameter.d.ts === +export interface Properties { +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.d.ts, 0, 0)) + + propertyA: number; +>propertyA : Symbol(Properties.propertyA, Decl(protectedMethodTypeofParameter.d.ts, 0, 29)) + + propertyB: string; +>propertyB : Symbol(Properties.propertyB, Decl(protectedMethodTypeofParameter.d.ts, 1, 22)) +} +export declare class A { +>A : Symbol(A, Decl(protectedMethodTypeofParameter.d.ts, 3, 1)) + + getPropertyValue_Ok(properties: Properties, propertyName: keyof Properties): Properties[typeof propertyName]; +>getPropertyValue_Ok : Symbol(A.getPropertyValue_Ok, Decl(protectedMethodTypeofParameter.d.ts, 4, 24)) +>properties : Symbol(properties, Decl(protectedMethodTypeofParameter.d.ts, 5, 24)) +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.d.ts, 0, 0)) +>propertyName : Symbol(propertyName, Decl(protectedMethodTypeofParameter.d.ts, 5, 47)) +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.d.ts, 0, 0)) +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.d.ts, 0, 0)) +>propertyName : Symbol(propertyName, Decl(protectedMethodTypeofParameter.d.ts, 5, 47)) + + protected getPropertyValue_Error(properties: Properties, propertyName: keyof Properties): Properties[typeof propertyName]; +>getPropertyValue_Error : Symbol(A.getPropertyValue_Error, Decl(protectedMethodTypeofParameter.d.ts, 5, 113)) +>properties : Symbol(properties, Decl(protectedMethodTypeofParameter.d.ts, 6, 37)) +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.d.ts, 0, 0)) +>propertyName : Symbol(propertyName, Decl(protectedMethodTypeofParameter.d.ts, 6, 60)) +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.d.ts, 0, 0)) +>Properties : Symbol(Properties, Decl(protectedMethodTypeofParameter.d.ts, 0, 0)) +>propertyName : Symbol(propertyName, Decl(protectedMethodTypeofParameter.d.ts, 6, 60)) +} + diff --git a/tests/baselines/reference/protectedMethodTypeofParameter.d.types b/tests/baselines/reference/protectedMethodTypeofParameter.d.types new file mode 100644 index 0000000000000..006bae46cbece --- /dev/null +++ b/tests/baselines/reference/protectedMethodTypeofParameter.d.types @@ -0,0 +1,37 @@ +//// [tests/cases/compiler/protectedMethodTypeofParameter.d.ts] //// + +=== protectedMethodTypeofParameter.d.ts === +export interface Properties { + propertyA: number; +>propertyA : number +> : ^^^^^^ + + propertyB: string; +>propertyB : string +> : ^^^^^^ +} +export declare class A { +>A : A +> : ^ + + getPropertyValue_Ok(properties: Properties, propertyName: keyof Properties): Properties[typeof propertyName]; +>getPropertyValue_Ok : (properties: Properties, propertyName: keyof Properties) => Properties[typeof propertyName] +> : ^ ^^ ^^ ^^ ^^^^^ +>properties : Properties +> : ^^^^^^^^^^ +>propertyName : keyof Properties +> : ^^^^^^^^^^^^^^^^ +>propertyName : keyof Properties +> : ^^^^^^^^^^^^^^^^ + + protected getPropertyValue_Error(properties: Properties, propertyName: keyof Properties): Properties[typeof propertyName]; +>getPropertyValue_Error : (properties: Properties, propertyName: keyof Properties) => Properties[typeof propertyName] +> : ^ ^^ ^^ ^^ ^^^^^ +>properties : Properties +> : ^^^^^^^^^^ +>propertyName : keyof Properties +> : ^^^^^^^^^^^^^^^^ +>propertyName : keyof Properties +> : ^^^^^^^^^^^^^^^^ +} + diff --git a/tests/cases/compiler/protectedMethodTypeofParameter.d.ts b/tests/cases/compiler/protectedMethodTypeofParameter.d.ts new file mode 100644 index 0000000000000..8215fb0ad5865 --- /dev/null +++ b/tests/cases/compiler/protectedMethodTypeofParameter.d.ts @@ -0,0 +1,8 @@ +export interface Properties { + propertyA: number; + propertyB: string; +} +export declare class A { + getPropertyValue_Ok(properties: Properties, propertyName: keyof Properties): Properties[typeof propertyName]; + protected getPropertyValue_Error(properties: Properties, propertyName: keyof Properties): Properties[typeof propertyName]; +}