diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 4464564837b8a..63673eea9631d 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -4530,14 +4530,9 @@ func (c *Checker) areTypeParametersIdentical(declarations []*ast.Node, targetPar func (c *Checker) checkBaseTypeAccessibility(t *Type, node *ast.Node) { signatures := c.getSignaturesOfType(t, SignatureKindConstruct) - if len(signatures) != 0 { - declaration := signatures[0].declaration - if declaration != nil && ast.HasModifier(declaration, ast.ModifierFlagsPrivate) { - typeClassDeclaration := ast.GetClassLikeDeclarationOfSymbol(t.symbol) - if !c.isNodeWithinClass(node, typeClassDeclaration) { - c.error(node, diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, c.getFullyQualifiedName(t.symbol, nil)) - } - } + accessibilityError := c.getConstructorAccessibilityError(node, signatures, ast.ModifierFlagsPrivate) + if accessibilityError != nil { + c.error(node, diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, c.getFullyQualifiedName(accessibilityError.declaringClass.symbol, nil)) } } @@ -8777,7 +8772,14 @@ func (c *Checker) resolveNewExpression(node *ast.Node, candidatesOutArray *[]*Si // that the user will not add any. constructSignatures := c.getSignaturesOfType(expressionType, SignatureKindConstruct) if len(constructSignatures) != 0 { - if !c.isConstructorAccessible(node, constructSignatures[0]) { + accessibilityError := c.getConstructorAccessibilityError(node, constructSignatures, ast.ModifierFlagsNonPublicAccessibilityModifier) + if accessibilityError != nil { + if accessibilityError.kind&ast.ModifierFlagsPrivate != 0 { + c.error(node, diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, c.TypeToString(accessibilityError.declaringClass)) + } + if accessibilityError.kind&ast.ModifierFlagsProtected != 0 { + c.error(node, diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, c.TypeToString(accessibilityError.declaringClass)) + } return c.resolveErrorCall(node) } // If the expression is a class of abstract type, or an abstract construct signature, @@ -8820,36 +8822,39 @@ func (c *Checker) resolveNewExpression(node *ast.Node, candidatesOutArray *[]*Si return c.resolveErrorCall(node) } -func (c *Checker) isConstructorAccessible(node *ast.Node, signature *Signature) bool { - if signature == nil || signature.declaration == nil { - return true - } - declaration := signature.declaration - modifiers := getSelectedModifierFlags(declaration, ast.ModifierFlagsNonPublicAccessibilityModifier) - // (1) Public constructors and (2) constructor functions are always accessible. - if modifiers == 0 || !ast.IsConstructorDeclaration(declaration) { - return true - } - declaringClassDeclaration := ast.GetClassLikeDeclarationOfSymbol(declaration.Parent.Symbol()) - declaringClass := c.getDeclaredTypeOfSymbol(declaration.Parent.Symbol()) - // A private or protected constructor can only be instantiated within its own class (or a subclass, for protected) - if !c.isNodeWithinClass(node, declaringClassDeclaration) { - containingClass := ast.GetContainingClass(node) - if containingClass != nil && modifiers&ast.ModifierFlagsProtected != 0 { - containingType := c.getDeclaredTypeOfSymbol(containingClass.Symbol()) - if c.typeHasProtectedAccessibleBase(declaration.Parent.Symbol(), containingType) { - return true - } +type constructorAccessibilityError struct { + kind ast.ModifierFlags + declaringClass *Type +} + +func (c *Checker) getConstructorAccessibilityError(node *ast.Node, signatures []*Signature, modifiersMask ast.ModifierFlags) *constructorAccessibilityError { + for _, signature := range signatures { + if signature.declaration == nil { + continue } - if modifiers&ast.ModifierFlagsPrivate != 0 { - c.error(node, diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, c.TypeToString(declaringClass)) + declaration := signature.declaration + modifiers := getSelectedModifierFlags(declaration, modifiersMask) + // (1) Public constructors and (2) constructor functions are always accessible. + if modifiers == 0 || !ast.IsConstructorDeclaration(declaration) { + continue } - if modifiers&ast.ModifierFlagsProtected != 0 { - c.error(node, diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, c.TypeToString(declaringClass)) + declaringClassDeclaration := ast.GetClassLikeDeclarationOfSymbol(declaration.Parent.Symbol()) + // A private or protected constructor can only be instantiated within its own class (or a subclass, for protected) + if !c.isNodeWithinClass(node, declaringClassDeclaration) { + containingClass := ast.GetContainingClass(node) + if containingClass != nil && modifiers&ast.ModifierFlagsProtected != 0 { + containingType := c.getTypeOfNode(containingClass) + if c.typeHasProtectedAccessibleBase(declaration.Parent.Symbol(), containingType) { + continue + } + } + return &constructorAccessibilityError{ + kind: modifiers, + declaringClass: c.getDeclaredTypeOfSymbol(declaration.Parent.Symbol()), + } } - return false } - return true + return nil } func (c *Checker) typeHasProtectedAccessibleBase(target *ast.Symbol, t *Type) bool { diff --git a/tsc/testdata/baselines/reference/compiler/extendPrivateConstructorClass2.errors.txt b/tsc/testdata/baselines/reference/compiler/extendPrivateConstructorClass2.errors.txt new file mode 100644 index 0000000000000..b8da61049b8c6 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/extendPrivateConstructorClass2.errors.txt @@ -0,0 +1,162 @@ +extendPrivateConstructorClass2.ts(10,1): error TS2673: Constructor of class 'A1' is private and only accessible within the class declaration. +extendPrivateConstructorClass2.ts(11,24): error TS2675: Cannot extend a class 'A1'. Class constructor is marked as private. +extendPrivateConstructorClass2.ts(22,1): error TS2673: Constructor of class 'B2' is private and only accessible within the class declaration. +extendPrivateConstructorClass2.ts(23,24): error TS2675: Cannot extend a class 'B2'. Class constructor is marked as private. +extendPrivateConstructorClass2.ts(33,26): error TS2675: Cannot extend a class 'j1'. Class constructor is marked as private. +extendPrivateConstructorClass2.ts(79,26): error TS2510: Base constructors must all have the same return type. +extendPrivateConstructorClass2.ts(98,22): error TS2510: Base constructors must all have the same return type. +extendPrivateConstructorClass2.ts(98,22): error TS2675: Cannot extend a class 'j10'. Class constructor is marked as private. +extendPrivateConstructorClass2.ts(129,22): error TS2675: Cannot extend a class 'j14'. Class constructor is marked as private. + + +==== extendPrivateConstructorClass2.ts (9 errors) ==== + class A1 { + private constructor(arg: string) {} + } + class B1 { + constructor(arg: number) {} + } + + declare const Cls1: typeof A1 & typeof B1; + + new Cls1(42); // error + ~~~~~~~~~~~~ +!!! error TS2673: Constructor of class 'A1' is private and only accessible within the class declaration. + class Derived1 extends Cls1 {} // error + ~~~~ +!!! error TS2675: Cannot extend a class 'A1'. Class constructor is marked as private. + + class A2 { + constructor(arg: string) {} + } + class B2 { + private constructor(arg: number) {} + } + + declare const Cls2: typeof A2 & typeof B2; + + new Cls2(42); // error + ~~~~~~~~~~~~ +!!! error TS2673: Constructor of class 'B2' is private and only accessible within the class declaration. + class Derived2 extends Cls2 {} // error + ~~~~ +!!! error TS2675: Cannot extend a class 'B2'. Class constructor is marked as private. + + // https://github.com/microsoft/TypeScript/issues/62614 + declare abstract class j1 { + private constructor(...args: any[]); + } + declare abstract class j2 { + private constructor(...args: any[]); + } + declare const jS: typeof j1 & typeof j2; + declare class j0 extends jS {} // error + ~~ +!!! error TS2675: Cannot extend a class 'j1'. Class constructor is marked as private. + + abstract class j3 { + private constructor(...args: any[]) {} + method1() { + abstract class j4 { + private constructor(...args: any[]) {} + method2() { + const jS: typeof j3 & typeof j4 = null!; + + // bizarre but ok + class j0 extends jS { + method1() {} + method2() {} + } + } + } + } + } + + abstract class j5 { + private constructor(...args: any[]) {} + method1() { + abstract class j6 { + private constructor(...args: any[]) {} + method2() {} + } + const jS: typeof j5 & typeof j6 = null!; + + // bizarre but ok too given the base is a result of a mixin + class j0 extends jS { + method1() {} + method2() {} + } + } + } + + abstract class j7 { + private constructor(arg: string) {} + method1() { + abstract class j8 { + private constructor(arg: number) {} + method2() { + const jS: typeof j7 & typeof j8 = null!; + + // error + class j0 extends jS { + ~~ +!!! error TS2510: Base constructors must all have the same return type. + method1() {} + method2() {} + } + } + } + } + } + + abstract class j9 { + private constructor(arg: string) {} + method1() { + abstract class j10 { + private constructor(arg: number) {} + method2() {} + } + const jS: typeof j9 & typeof j10 = null!; + + // error + class j0 extends jS { + ~~ +!!! error TS2510: Base constructors must all have the same return type. + ~~ +!!! error TS2675: Cannot extend a class 'j10'. Class constructor is marked as private. + method1() {} + method2() {} + } + } + } + + abstract class j11 { + private constructor(arg: string) {} + static { + abstract class j12 { + private constructor(arg: number) {} + static { + const jS: typeof j11 & typeof j12 = null!; + + // ok + class j0 extends jS {} + } + } + } + } + + abstract class j13 { + private constructor(arg: string) {} + static { + abstract class j14 { + private constructor(arg: number) {} + } + const jS: typeof j13 & typeof j14 = null!; + + // error + class j0 extends jS {} + ~~ +!!! error TS2675: Cannot extend a class 'j14'. Class constructor is marked as private. + } + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/extendPrivateConstructorClass2.symbols b/tsc/testdata/baselines/reference/compiler/extendPrivateConstructorClass2.symbols new file mode 100644 index 0000000000000..08ec1ab380651 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/extendPrivateConstructorClass2.symbols @@ -0,0 +1,280 @@ +//// [tests/cases/compiler/extendPrivateConstructorClass2.ts] //// + +=== extendPrivateConstructorClass2.ts === +class A1 { +>A1 : Symbol(A1, Decl(extendPrivateConstructorClass2.ts, 0, 0)) + + private constructor(arg: string) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 1, 22)) +} +class B1 { +>B1 : Symbol(B1, Decl(extendPrivateConstructorClass2.ts, 2, 1)) + + constructor(arg: number) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 4, 14)) +} + +declare const Cls1: typeof A1 & typeof B1; +>Cls1 : Symbol(Cls1, Decl(extendPrivateConstructorClass2.ts, 7, 13)) +>A1 : Symbol(A1, Decl(extendPrivateConstructorClass2.ts, 0, 0)) +>B1 : Symbol(B1, Decl(extendPrivateConstructorClass2.ts, 2, 1)) + +new Cls1(42); // error +>Cls1 : Symbol(Cls1, Decl(extendPrivateConstructorClass2.ts, 7, 13)) + +class Derived1 extends Cls1 {} // error +>Derived1 : Symbol(Derived1, Decl(extendPrivateConstructorClass2.ts, 9, 13)) +>Cls1 : Symbol(Cls1, Decl(extendPrivateConstructorClass2.ts, 7, 13)) + +class A2 { +>A2 : Symbol(A2, Decl(extendPrivateConstructorClass2.ts, 10, 30)) + + constructor(arg: string) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 13, 14)) +} +class B2 { +>B2 : Symbol(B2, Decl(extendPrivateConstructorClass2.ts, 14, 1)) + + private constructor(arg: number) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 16, 22)) +} + +declare const Cls2: typeof A2 & typeof B2; +>Cls2 : Symbol(Cls2, Decl(extendPrivateConstructorClass2.ts, 19, 13)) +>A2 : Symbol(A2, Decl(extendPrivateConstructorClass2.ts, 10, 30)) +>B2 : Symbol(B2, Decl(extendPrivateConstructorClass2.ts, 14, 1)) + +new Cls2(42); // error +>Cls2 : Symbol(Cls2, Decl(extendPrivateConstructorClass2.ts, 19, 13)) + +class Derived2 extends Cls2 {} // error +>Derived2 : Symbol(Derived2, Decl(extendPrivateConstructorClass2.ts, 21, 13)) +>Cls2 : Symbol(Cls2, Decl(extendPrivateConstructorClass2.ts, 19, 13)) + +// https://github.com/microsoft/TypeScript/issues/62614 +declare abstract class j1 { +>j1 : Symbol(j1, Decl(extendPrivateConstructorClass2.ts, 22, 30)) + + private constructor(...args: any[]); +>args : Symbol(args, Decl(extendPrivateConstructorClass2.ts, 26, 22)) +} +declare abstract class j2 { +>j2 : Symbol(j2, Decl(extendPrivateConstructorClass2.ts, 27, 1)) + + private constructor(...args: any[]); +>args : Symbol(args, Decl(extendPrivateConstructorClass2.ts, 29, 22)) +} +declare const jS: typeof j1 & typeof j2; +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 31, 13)) +>j1 : Symbol(j1, Decl(extendPrivateConstructorClass2.ts, 22, 30)) +>j2 : Symbol(j2, Decl(extendPrivateConstructorClass2.ts, 27, 1)) + +declare class j0 extends jS {} // error +>j0 : Symbol(j0, Decl(extendPrivateConstructorClass2.ts, 31, 40)) +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 31, 13)) + +abstract class j3 { +>j3 : Symbol(j3, Decl(extendPrivateConstructorClass2.ts, 32, 30)) + + private constructor(...args: any[]) {} +>args : Symbol(args, Decl(extendPrivateConstructorClass2.ts, 35, 22)) + + method1() { +>method1 : Symbol(j3.method1, Decl(extendPrivateConstructorClass2.ts, 35, 40)) + + abstract class j4 { +>j4 : Symbol(j4, Decl(extendPrivateConstructorClass2.ts, 36, 13)) + + private constructor(...args: any[]) {} +>args : Symbol(args, Decl(extendPrivateConstructorClass2.ts, 38, 26)) + + method2() { +>method2 : Symbol(j4.method2, Decl(extendPrivateConstructorClass2.ts, 38, 44)) + + const jS: typeof j3 & typeof j4 = null!; +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 40, 13)) +>j3 : Symbol(j3, Decl(extendPrivateConstructorClass2.ts, 32, 30)) +>j4 : Symbol(j4, Decl(extendPrivateConstructorClass2.ts, 36, 13)) + + // bizarre but ok + class j0 extends jS { +>j0 : Symbol(j0, Decl(extendPrivateConstructorClass2.ts, 40, 48)) +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 40, 13)) + + method1() {} +>method1 : Symbol(j0.method1, Decl(extendPrivateConstructorClass2.ts, 43, 29)) + + method2() {} +>method2 : Symbol(j0.method2, Decl(extendPrivateConstructorClass2.ts, 44, 22)) + } + } + } + } +} + +abstract class j5 { +>j5 : Symbol(j5, Decl(extendPrivateConstructorClass2.ts, 50, 1)) + + private constructor(...args: any[]) {} +>args : Symbol(args, Decl(extendPrivateConstructorClass2.ts, 53, 22)) + + method1() { +>method1 : Symbol(j5.method1, Decl(extendPrivateConstructorClass2.ts, 53, 40)) + + abstract class j6 { +>j6 : Symbol(j6, Decl(extendPrivateConstructorClass2.ts, 54, 13)) + + private constructor(...args: any[]) {} +>args : Symbol(args, Decl(extendPrivateConstructorClass2.ts, 56, 26)) + + method2() {} +>method2 : Symbol(j6.method2, Decl(extendPrivateConstructorClass2.ts, 56, 44)) + } + const jS: typeof j5 & typeof j6 = null!; +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 59, 9)) +>j5 : Symbol(j5, Decl(extendPrivateConstructorClass2.ts, 50, 1)) +>j6 : Symbol(j6, Decl(extendPrivateConstructorClass2.ts, 54, 13)) + + // bizarre but ok too given the base is a result of a mixin + class j0 extends jS { +>j0 : Symbol(j0, Decl(extendPrivateConstructorClass2.ts, 59, 44)) +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 59, 9)) + + method1() {} +>method1 : Symbol(j0.method1, Decl(extendPrivateConstructorClass2.ts, 62, 25)) + + method2() {} +>method2 : Symbol(j0.method2, Decl(extendPrivateConstructorClass2.ts, 63, 18)) + } + } +} + +abstract class j7 { +>j7 : Symbol(j7, Decl(extendPrivateConstructorClass2.ts, 67, 1)) + + private constructor(arg: string) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 70, 22)) + + method1() { +>method1 : Symbol(j7.method1, Decl(extendPrivateConstructorClass2.ts, 70, 37)) + + abstract class j8 { +>j8 : Symbol(j8, Decl(extendPrivateConstructorClass2.ts, 71, 13)) + + private constructor(arg: number) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 73, 26)) + + method2() { +>method2 : Symbol(j8.method2, Decl(extendPrivateConstructorClass2.ts, 73, 41)) + + const jS: typeof j7 & typeof j8 = null!; +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 75, 13)) +>j7 : Symbol(j7, Decl(extendPrivateConstructorClass2.ts, 67, 1)) +>j8 : Symbol(j8, Decl(extendPrivateConstructorClass2.ts, 71, 13)) + + // error + class j0 extends jS { +>j0 : Symbol(j0, Decl(extendPrivateConstructorClass2.ts, 75, 48)) +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 75, 13)) + + method1() {} +>method1 : Symbol(j0.method1, Decl(extendPrivateConstructorClass2.ts, 78, 29)) + + method2() {} +>method2 : Symbol(j0.method2, Decl(extendPrivateConstructorClass2.ts, 79, 22)) + } + } + } + } +} + +abstract class j9 { +>j9 : Symbol(j9, Decl(extendPrivateConstructorClass2.ts, 85, 1)) + + private constructor(arg: string) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 88, 22)) + + method1() { +>method1 : Symbol(j9.method1, Decl(extendPrivateConstructorClass2.ts, 88, 37)) + + abstract class j10 { +>j10 : Symbol(j10, Decl(extendPrivateConstructorClass2.ts, 89, 13)) + + private constructor(arg: number) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 91, 26)) + + method2() {} +>method2 : Symbol(j10.method2, Decl(extendPrivateConstructorClass2.ts, 91, 41)) + } + const jS: typeof j9 & typeof j10 = null!; +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 94, 9)) +>j9 : Symbol(j9, Decl(extendPrivateConstructorClass2.ts, 85, 1)) +>j10 : Symbol(j10, Decl(extendPrivateConstructorClass2.ts, 89, 13)) + + // error + class j0 extends jS { +>j0 : Symbol(j0, Decl(extendPrivateConstructorClass2.ts, 94, 45)) +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 94, 9)) + + method1() {} +>method1 : Symbol(j0.method1, Decl(extendPrivateConstructorClass2.ts, 97, 25)) + + method2() {} +>method2 : Symbol(j0.method2, Decl(extendPrivateConstructorClass2.ts, 98, 18)) + } + } +} + +abstract class j11 { +>j11 : Symbol(j11, Decl(extendPrivateConstructorClass2.ts, 102, 1)) + + private constructor(arg: string) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 105, 22)) + + static { + abstract class j12 { +>j12 : Symbol(j12, Decl(extendPrivateConstructorClass2.ts, 106, 10)) + + private constructor(arg: number) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 108, 26)) + + static { + const jS: typeof j11 & typeof j12 = null!; +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 110, 13)) +>j11 : Symbol(j11, Decl(extendPrivateConstructorClass2.ts, 102, 1)) +>j12 : Symbol(j12, Decl(extendPrivateConstructorClass2.ts, 106, 10)) + + // ok + class j0 extends jS {} +>j0 : Symbol(j0, Decl(extendPrivateConstructorClass2.ts, 110, 50)) +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 110, 13)) + } + } + } +} + +abstract class j13 { +>j13 : Symbol(j13, Decl(extendPrivateConstructorClass2.ts, 117, 1)) + + private constructor(arg: string) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 120, 22)) + + static { + abstract class j14 { +>j14 : Symbol(j14, Decl(extendPrivateConstructorClass2.ts, 121, 10)) + + private constructor(arg: number) {} +>arg : Symbol(arg, Decl(extendPrivateConstructorClass2.ts, 123, 26)) + } + const jS: typeof j13 & typeof j14 = null!; +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 125, 9)) +>j13 : Symbol(j13, Decl(extendPrivateConstructorClass2.ts, 117, 1)) +>j14 : Symbol(j14, Decl(extendPrivateConstructorClass2.ts, 121, 10)) + + // error + class j0 extends jS {} +>j0 : Symbol(j0, Decl(extendPrivateConstructorClass2.ts, 125, 46)) +>jS : Symbol(jS, Decl(extendPrivateConstructorClass2.ts, 125, 9)) + } +} + diff --git a/tsc/testdata/baselines/reference/compiler/extendPrivateConstructorClass2.types b/tsc/testdata/baselines/reference/compiler/extendPrivateConstructorClass2.types new file mode 100644 index 0000000000000..33b7cbada11bb --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/extendPrivateConstructorClass2.types @@ -0,0 +1,290 @@ +//// [tests/cases/compiler/extendPrivateConstructorClass2.ts] //// + +=== extendPrivateConstructorClass2.ts === +class A1 { +>A1 : A1 + + private constructor(arg: string) {} +>arg : string +} +class B1 { +>B1 : B1 + + constructor(arg: number) {} +>arg : number +} + +declare const Cls1: typeof A1 & typeof B1; +>Cls1 : typeof A1 & typeof B1 +>A1 : typeof A1 +>B1 : typeof B1 + +new Cls1(42); // error +>new Cls1(42) : any +>Cls1 : typeof A1 & typeof B1 +>42 : 42 + +class Derived1 extends Cls1 {} // error +>Derived1 : Derived1 +>Cls1 : A1 + +class A2 { +>A2 : A2 + + constructor(arg: string) {} +>arg : string +} +class B2 { +>B2 : B2 + + private constructor(arg: number) {} +>arg : number +} + +declare const Cls2: typeof A2 & typeof B2; +>Cls2 : typeof A2 & typeof B2 +>A2 : typeof A2 +>B2 : typeof B2 + +new Cls2(42); // error +>new Cls2(42) : any +>Cls2 : typeof A2 & typeof B2 +>42 : 42 + +class Derived2 extends Cls2 {} // error +>Derived2 : Derived2 +>Cls2 : A2 + +// https://github.com/microsoft/TypeScript/issues/62614 +declare abstract class j1 { +>j1 : j1 + + private constructor(...args: any[]); +>args : any[] +} +declare abstract class j2 { +>j2 : j2 + + private constructor(...args: any[]); +>args : any[] +} +declare const jS: typeof j1 & typeof j2; +>jS : typeof j1 & typeof j2 +>j1 : typeof j1 +>j2 : typeof j2 + +declare class j0 extends jS {} // error +>j0 : j0 +>jS : j1 & j2 + +abstract class j3 { +>j3 : j3 + + private constructor(...args: any[]) {} +>args : any[] + + method1() { +>method1 : () => void + + abstract class j4 { +>j4 : j4 + + private constructor(...args: any[]) {} +>args : any[] + + method2() { +>method2 : () => void + + const jS: typeof j3 & typeof j4 = null!; +>jS : typeof j3 & typeof j4 +>j3 : typeof j3 +>j4 : typeof j4 +>null! : never + + // bizarre but ok + class j0 extends jS { +>j0 : j0 +>jS : j3 & j4 + + method1() {} +>method1 : () => void + + method2() {} +>method2 : () => void + } + } + } + } +} + +abstract class j5 { +>j5 : j5 + + private constructor(...args: any[]) {} +>args : any[] + + method1() { +>method1 : () => void + + abstract class j6 { +>j6 : j6 + + private constructor(...args: any[]) {} +>args : any[] + + method2() {} +>method2 : () => void + } + const jS: typeof j5 & typeof j6 = null!; +>jS : typeof j5 & typeof j6 +>j5 : typeof j5 +>j6 : typeof j6 +>null! : never + + // bizarre but ok too given the base is a result of a mixin + class j0 extends jS { +>j0 : j0 +>jS : j5 & j6 + + method1() {} +>method1 : () => void + + method2() {} +>method2 : () => void + } + } +} + +abstract class j7 { +>j7 : j7 + + private constructor(arg: string) {} +>arg : string + + method1() { +>method1 : () => void + + abstract class j8 { +>j8 : j8 + + private constructor(arg: number) {} +>arg : number + + method2() { +>method2 : () => void + + const jS: typeof j7 & typeof j8 = null!; +>jS : typeof j7 & typeof j8 +>j7 : typeof j7 +>j8 : typeof j8 +>null! : never + + // error + class j0 extends jS { +>j0 : j0 +>jS : j7 + + method1() {} +>method1 : () => void + + method2() {} +>method2 : () => void + } + } + } + } +} + +abstract class j9 { +>j9 : j9 + + private constructor(arg: string) {} +>arg : string + + method1() { +>method1 : () => void + + abstract class j10 { +>j10 : j10 + + private constructor(arg: number) {} +>arg : number + + method2() {} +>method2 : () => void + } + const jS: typeof j9 & typeof j10 = null!; +>jS : typeof j9 & typeof j10 +>j9 : typeof j9 +>j10 : typeof j10 +>null! : never + + // error + class j0 extends jS { +>j0 : j0 +>jS : j9 + + method1() {} +>method1 : () => void + + method2() {} +>method2 : () => void + } + } +} + +abstract class j11 { +>j11 : j11 + + private constructor(arg: string) {} +>arg : string + + static { + abstract class j12 { +>j12 : j12 + + private constructor(arg: number) {} +>arg : number + + static { + const jS: typeof j11 & typeof j12 = null!; +>jS : typeof j11 & typeof j12 +>j11 : typeof j11 +>j12 : typeof j12 +>null! : never + + // ok + class j0 extends jS {} +>j0 : j0 +>jS : j11 + } + } + } +} + +abstract class j13 { +>j13 : j13 + + private constructor(arg: string) {} +>arg : string + + static { + abstract class j14 { +>j14 : j14 + + private constructor(arg: number) {} +>arg : number + } + const jS: typeof j13 & typeof j14 = null!; +>jS : typeof j13 & typeof j14 +>j13 : typeof j13 +>j14 : typeof j14 +>null! : never + + // error + class j0 extends jS {} +>j0 : j0 +>jS : j13 + } +} + diff --git a/tsc/testdata/tests/cases/compiler/extendPrivateConstructorClass2.ts b/tsc/testdata/tests/cases/compiler/extendPrivateConstructorClass2.ts new file mode 100644 index 0000000000000..22b81c58ca466 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/extendPrivateConstructorClass2.ts @@ -0,0 +1,134 @@ +// @strict: true +// @noEmit: true + +class A1 { + private constructor(arg: string) {} +} +class B1 { + constructor(arg: number) {} +} + +declare const Cls1: typeof A1 & typeof B1; + +new Cls1(42); // error +class Derived1 extends Cls1 {} // error + +class A2 { + constructor(arg: string) {} +} +class B2 { + private constructor(arg: number) {} +} + +declare const Cls2: typeof A2 & typeof B2; + +new Cls2(42); // error +class Derived2 extends Cls2 {} // error + +// https://github.com/microsoft/TypeScript/issues/62614 +declare abstract class j1 { + private constructor(...args: any[]); +} +declare abstract class j2 { + private constructor(...args: any[]); +} +declare const jS: typeof j1 & typeof j2; +declare class j0 extends jS {} // error + +abstract class j3 { + private constructor(...args: any[]) {} + method1() { + abstract class j4 { + private constructor(...args: any[]) {} + method2() { + const jS: typeof j3 & typeof j4 = null!; + + // bizarre but ok + class j0 extends jS { + method1() {} + method2() {} + } + } + } + } +} + +abstract class j5 { + private constructor(...args: any[]) {} + method1() { + abstract class j6 { + private constructor(...args: any[]) {} + method2() {} + } + const jS: typeof j5 & typeof j6 = null!; + + // bizarre but ok too given the base is a result of a mixin + class j0 extends jS { + method1() {} + method2() {} + } + } +} + +abstract class j7 { + private constructor(arg: string) {} + method1() { + abstract class j8 { + private constructor(arg: number) {} + method2() { + const jS: typeof j7 & typeof j8 = null!; + + // error + class j0 extends jS { + method1() {} + method2() {} + } + } + } + } +} + +abstract class j9 { + private constructor(arg: string) {} + method1() { + abstract class j10 { + private constructor(arg: number) {} + method2() {} + } + const jS: typeof j9 & typeof j10 = null!; + + // error + class j0 extends jS { + method1() {} + method2() {} + } + } +} + +abstract class j11 { + private constructor(arg: string) {} + static { + abstract class j12 { + private constructor(arg: number) {} + static { + const jS: typeof j11 & typeof j12 = null!; + + // ok + class j0 extends jS {} + } + } + } +} + +abstract class j13 { + private constructor(arg: string) {} + static { + abstract class j14 { + private constructor(arg: number) {} + } + const jS: typeof j13 & typeof j14 = null!; + + // error + class j0 extends jS {} + } +}