diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 438e46eca11b6..f5965b1699758 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33868,7 +33868,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // get the original type -- represented as the type constraint of the 'this' type containingType = (containingType as TypeParameter).isThisType ? getConstraintOfTypeParameter(containingType as TypeParameter)! : getBaseConstraintOfType(containingType as TypeParameter)!; // TODO: GH#18217 Use a different variable that's allowed to be undefined } - if (!containingType || !hasBaseType(containingType, enclosingClass)) { + if (!containingType || !hasBaseType(containingType, enclosingClass) && !isNodeWithinClass(location, getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!)!)) { if (errorNode) { error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1_This_is_an_instance_of_class_2, symbolToString(prop), typeToString(enclosingClass), typeToString(containingType)); } diff --git a/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedSubclass2.symbols b/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedSubclass2.symbols new file mode 100644 index 0000000000000..5b50d1b6ec317 --- /dev/null +++ b/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedSubclass2.symbols @@ -0,0 +1,72 @@ +//// [tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinNestedSubclass2.ts] //// + +=== protectedClassPropertyAccessibleWithinNestedSubclass2.ts === +// https://github.com/microsoft/TypeScript/issues/59989 + +export class Foo { +>Foo : Symbol(Foo, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 0, 0)) + + protected thisIsProtected = 1; +>thisIsProtected : Symbol(Foo.thisIsProtected, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 2, 18)) + + private thisIsPrivate = 1; +>thisIsPrivate : Symbol(Foo.thisIsPrivate, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 3, 32)) + + bar(): Foo { +>bar : Symbol(Foo.bar, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 4, 28)) +>Foo : Symbol(Foo, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 0, 0)) + + const that = this; +>that : Symbol(that, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 7, 9)) +>this : Symbol(Foo, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 0, 0)) + + return new (class extends Foo { +>Foo : Symbol(Foo, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 0, 0)) + + something() { +>something : Symbol((Anonymous class).something, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 9, 35)) + + return that.thisIsPrivate + that.thisIsProtected; // ok +>that.thisIsPrivate : Symbol(Foo.thisIsPrivate, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 3, 32)) +>that : Symbol(that, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 7, 9)) +>thisIsPrivate : Symbol(Foo.thisIsPrivate, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 3, 32)) +>that.thisIsProtected : Symbol(Foo.thisIsProtected, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 2, 18)) +>that : Symbol(that, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 7, 9)) +>thisIsProtected : Symbol(Foo.thisIsProtected, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 2, 18)) + } + })(); + } +} + +export class Foo2 { +>Foo2 : Symbol(Foo2, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 15, 1)) + + protected thisIsProtected = 1; +>thisIsProtected : Symbol(Foo2.thisIsProtected, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 17, 19)) + + private thisIsPrivate = 1; +>thisIsPrivate : Symbol(Foo2.thisIsPrivate, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 18, 32)) + + bar() { +>bar : Symbol(Foo2.bar, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 19, 28)) + + const that = this; +>that : Symbol(that, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 22, 9)) +>this : Symbol(Foo2, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 15, 1)) + + return new (class { + something() { +>something : Symbol((Anonymous class).something, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 24, 23)) + + return that.thisIsPrivate + that.thisIsProtected; // ok +>that.thisIsPrivate : Symbol(Foo2.thisIsPrivate, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 18, 32)) +>that : Symbol(that, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 22, 9)) +>thisIsPrivate : Symbol(Foo2.thisIsPrivate, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 18, 32)) +>that.thisIsProtected : Symbol(Foo2.thisIsProtected, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 17, 19)) +>that : Symbol(that, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 22, 9)) +>thisIsProtected : Symbol(Foo2.thisIsProtected, Decl(protectedClassPropertyAccessibleWithinNestedSubclass2.ts, 17, 19)) + } + })(); + } +} + diff --git a/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedSubclass2.types b/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedSubclass2.types new file mode 100644 index 0000000000000..7e616bdaeaf0d --- /dev/null +++ b/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedSubclass2.types @@ -0,0 +1,123 @@ +//// [tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinNestedSubclass2.ts] //// + +=== protectedClassPropertyAccessibleWithinNestedSubclass2.ts === +// https://github.com/microsoft/TypeScript/issues/59989 + +export class Foo { +>Foo : Foo +> : ^^^ + + protected thisIsProtected = 1; +>thisIsProtected : number +> : ^^^^^^ +>1 : 1 +> : ^ + + private thisIsPrivate = 1; +>thisIsPrivate : number +> : ^^^^^^ +>1 : 1 +> : ^ + + bar(): Foo { +>bar : () => Foo +> : ^^^^^^ + + const that = this; +>that : this +> : ^^^^ +>this : this +> : ^^^^ + + return new (class extends Foo { +>new (class extends Foo { something() { return that.thisIsPrivate + that.thisIsProtected; // ok } })() : (Anonymous class) +> : ^^^^^^^^^^^^^^^^^ +>(class extends Foo { something() { return that.thisIsPrivate + that.thisIsProtected; // ok } }) : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>class extends Foo { something() { return that.thisIsPrivate + that.thisIsProtected; // ok } } : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>Foo : Foo +> : ^^^ + + something() { +>something : () => number +> : ^^^^^^^^^^^^ + + return that.thisIsPrivate + that.thisIsProtected; // ok +>that.thisIsPrivate + that.thisIsProtected : number +> : ^^^^^^ +>that.thisIsPrivate : number +> : ^^^^^^ +>that : this +> : ^^^^ +>thisIsPrivate : number +> : ^^^^^^ +>that.thisIsProtected : number +> : ^^^^^^ +>that : this +> : ^^^^ +>thisIsProtected : number +> : ^^^^^^ + } + })(); + } +} + +export class Foo2 { +>Foo2 : Foo2 +> : ^^^^ + + protected thisIsProtected = 1; +>thisIsProtected : number +> : ^^^^^^ +>1 : 1 +> : ^ + + private thisIsPrivate = 1; +>thisIsPrivate : number +> : ^^^^^^ +>1 : 1 +> : ^ + + bar() { +>bar : () => (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^ + + const that = this; +>that : this +> : ^^^^ +>this : this +> : ^^^^ + + return new (class { +>new (class { something() { return that.thisIsPrivate + that.thisIsProtected; // ok } })() : (Anonymous class) +> : ^^^^^^^^^^^^^^^^^ +>(class { something() { return that.thisIsPrivate + that.thisIsProtected; // ok } }) : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>class { something() { return that.thisIsPrivate + that.thisIsProtected; // ok } } : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + something() { +>something : () => number +> : ^^^^^^^^^^^^ + + return that.thisIsPrivate + that.thisIsProtected; // ok +>that.thisIsPrivate + that.thisIsProtected : number +> : ^^^^^^ +>that.thisIsPrivate : number +> : ^^^^^^ +>that : this +> : ^^^^ +>thisIsPrivate : number +> : ^^^^^^ +>that.thisIsProtected : number +> : ^^^^^^ +>that : this +> : ^^^^ +>thisIsProtected : number +> : ^^^^^^ + } + })(); + } +} + diff --git a/tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinNestedSubclass2.ts b/tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinNestedSubclass2.ts new file mode 100644 index 0000000000000..cc3eb8798b563 --- /dev/null +++ b/tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinNestedSubclass2.ts @@ -0,0 +1,34 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/59989 + +export class Foo { + protected thisIsProtected = 1; + private thisIsPrivate = 1; + + bar(): Foo { + const that = this; + + return new (class extends Foo { + something() { + return that.thisIsPrivate + that.thisIsProtected; // ok + } + })(); + } +} + +export class Foo2 { + protected thisIsProtected = 1; + private thisIsPrivate = 1; + + bar() { + const that = this; + + return new (class { + something() { + return that.thisIsPrivate + that.thisIsProtected; // ok + } + })(); + } +}