Skip to content

Conversation

@PaulyBearCoding
Copy link

Fixes #62738

The Bug

TypeScript incorrectly rejects this valid pattern:

class MyClass {
  protected myMethod() {}
}

class MyDerivedClass extends MyClass {
  static {
    this.prototype.myMethod = function(this: MyDerivedClass) {
      MyClass.prototype.myMethod.call(this); // ❌ Error TS2446
    }
  }
}

Error:

Property 'myMethod' is protected and only accessible through an instance of
class 'MyDerivedClass'. This is an instance of class 'MyClass'.(2446)

Why this should work:

  • Function has explicit this: MyDerivedClass parameter
  • MyDerivedClass extends MyClass
  • TypeScript validates explicit this at call sites
  • Pattern is type-safe

Maintainer confirmed: @RyanCavanaugh commented: "This specific error seems wrong"


The Fix

Modified checkPropertyAccessibility() in src/compiler/checker.ts:

1. Check explicit this parameters first (for instance members only)

// For instance members, check explicit 'this' parameter first
if (!(flags & ModifierFlags.Static)) {
    enclosingClass = getEnclosingClassFromThisParameter(location);
    fromExplicitThis = !!enclosingClass;
}

// Then check class hierarchy
if (!enclosingClass) {
    enclosingClass = forEachEnclosingClass(location, ...);
}

2. Allow bidirectional type relationship when explicit this present

// Standard: containingType must be subclass of enclosingClass
// New: OR enclosingClass is subclass of containingType (when explicit 'this')
if (!(hasBaseType(containingType, enclosingClass) ||
      (fromExplicitThis && hasBaseType(enclosingClass, containingType)))) {
    error(...);
}

Why This Works

When you write function(this: DerivedClass), TypeScript already validates the type at call sites:

const fn = function(this: Derived) {
    Base.prototype.method.call(this);
};

fn.call(new Derived());  // ✅ Type-safe
fn.call(new Base());     // ❌ Compile error

The fix recognizes that if TypeScript already guarantees this is the correct type, then accessing base class protected members is safe.


Test Results

TypeScript's test suites:

conformance/classes: 3,732 passing
conformance/types: 5,076 passing
members/accessibility: 132 passing

Before fix:

$ tsc repro-62738.ts
repro-62738.ts(27,25): error TS2446

After fix:

$ tsc repro-62738.ts
# Compiles successfully

What Still Errors (Security Maintained)

// ❌ Unrelated class
class Unrelated {
    test() {
        const fn = function(this: Unrelated) {
            Base.prototype.method.call(this); // Error TS2445
        };
    }
}

// ❌ External access
const instance = new Derived();
instance.method(); // Error TS2445

// ❌ Static protected members
function fn(this: MyClass) {
    MyClass.staticProtected = 1; // Error TS2445
}

Files Changed

Modified:

  • src/compiler/checker.ts (40 lines)

Added:

  • tests/cases/conformance/classes/members/accessibility/protectedAccessViaExplicitThisParameter.ts
  • Corresponding baseline files

Breaking Changes

None.

Fixes microsoft#62738

When accessing a base class protected member via .call(this) or
.apply(this) with an explicit this parameter typed as a derived
class, TypeScript now correctly allows the access.

Previously, accessing BaseClass.prototype.method.call(this) inside
a function with this: DerivedClass incorrectly raised error TS2446.
The error claimed the access was invalid, but this pattern is type-safe
because the explicit this parameter ensures the correct type.

Changes:
- Check explicit 'this' parameters before enclosing class hierarchy
  for instance members only (static members unaffected)
- Track whether enclosingClass came from explicit 'this' parameter
- Allow bidirectional type relationship when explicit 'this' present

The fix maintains protected member security while allowing the valid
pattern confirmed by maintainer in the issue discussion.
@github-project-automation github-project-automation bot moved this to Not started in PR Backlog Nov 13, 2025
@typescript-bot typescript-bot added the For Backlog Bug PRs that fix a backlog bug label Nov 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Backlog Bug PRs that fix a backlog bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

Access base class protected methods in static block

2 participants