Skip to content

Commit 8ef9599

Browse files
committed
Allow extending and instantiating a private or protected class within itself
1 parent d0843e1 commit 8ef9599

1 file changed

Lines changed: 23 additions & 8 deletions

File tree

src/compiler/checker.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10192,12 +10192,11 @@ namespace ts {
1019210192
return true;
1019310193
}
1019410194

10195+
const declaringClassDeclaration = <ClassLikeDeclaration>getClassLikeDeclarationOfSymbol(declaration.parent.symbol);
1019510196
const declaringClass = <InterfaceType>getDeclaredTypeOfSymbol(declaration.parent.symbol);
10196-
const enclosingClassDeclaration = getContainingClass(node);
10197-
const enclosingClass = enclosingClassDeclaration ? <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClassDeclaration)) : undefined;
1019810197

1019910198
// A private or protected constructor can only be instantiated within it's own class
10200-
if (declaringClass !== enclosingClass) {
10199+
if (!isNodeWithinClass(node, declaringClassDeclaration)) {
1020110200
if (flags & NodeFlags.Private) {
1020210201
error(node, Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, typeToString(declaringClass));
1020310202
}
@@ -14076,11 +14075,14 @@ namespace ts {
1407614075
}
1407714076

1407814077
function checkBaseTypeAccessibility(type: ObjectType, node: ExpressionWithTypeArguments) {
14079-
const signatures = getSignaturesOfType(type, SignatureKind.Construct);
14080-
if (signatures.length) {
14081-
const declaration = signatures[0].declaration;
14082-
if (declaration && declaration.flags & NodeFlags.Private) {
14083-
error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, (<Identifier>node.expression).text);
14078+
const typeClassDeclaration = <ClassLikeDeclaration>getClassLikeDeclarationOfSymbol(type.symbol);
14079+
if (!isNodeWithinClass(node, typeClassDeclaration)) {
14080+
const signatures = getSignaturesOfType(type, SignatureKind.Construct);
14081+
if (signatures.length) {
14082+
const declaration = signatures[0].declaration;
14083+
if (declaration && declaration.flags & NodeFlags.Private) {
14084+
error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, (<Identifier>node.expression).text);
14085+
}
1408414086
}
1408514087
}
1408614088
}
@@ -15408,6 +15410,19 @@ namespace ts {
1540815410
return node.parent && node.parent.kind === SyntaxKind.ExpressionWithTypeArguments;
1540915411
}
1541015412

15413+
function isNodeWithinClass(node: Node, classDeclaration: ClassLikeDeclaration) {
15414+
while (true) {
15415+
const containingClass = getContainingClass(node);
15416+
if (!containingClass) {
15417+
return false;
15418+
}
15419+
if (containingClass === classDeclaration) {
15420+
return true;
15421+
}
15422+
node = containingClass;
15423+
}
15424+
}
15425+
1541115426
function getLeftSideOfImportEqualsOrExportAssignment(nodeOnRightSide: EntityName): ImportEqualsDeclaration | ExportAssignment {
1541215427
while (nodeOnRightSide.parent.kind === SyntaxKind.QualifiedName) {
1541315428
nodeOnRightSide = <QualifiedName>nodeOnRightSide.parent;

0 commit comments

Comments
 (0)