diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 48bc0da113816..e77aa179c7f7b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -37056,7 +37056,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // that the user will not add any. const constructSignatures = getSignaturesOfType(expressionType, SignatureKind.Construct); if (constructSignatures.length) { - if (!isConstructorAccessible(node, constructSignatures[0])) { + const accessibilityError = getConstructorAccessibilityError(node, constructSignatures, ModifierFlags.NonPublicAccessibilityModifier); + if (accessibilityError) { + if (accessibilityError.kind & ModifierFlags.Private) { + error(node, Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, typeToString(accessibilityError.declaringClass)); + } + if (accessibilityError.kind & ModifierFlags.Protected) { + error(node, Diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, typeToString(accessibilityError.declaringClass)); + } return resolveErrorCall(node); } // If the expression is a class of abstract type, or an abstract construct signature, @@ -37137,41 +37144,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeHasProtectedAccessibleBase(target, firstBase as InterfaceType); } - function isConstructorAccessible(node: NewExpression, signature: Signature) { - if (!signature || !signature.declaration) { - return true; - } - - const declaration = signature.declaration; - const modifiers = getSelectedEffectiveModifierFlags(declaration, ModifierFlags.NonPublicAccessibilityModifier); + function getConstructorAccessibilityError(node: Expression, signatures: readonly Signature[], modifiersMask: ModifierFlags) { + for (const signature of signatures) { + if (!signature.declaration) { + continue; + } + const declaration = signature.declaration; + const modifiers = getSelectedEffectiveModifierFlags(declaration, modifiersMask); - // (1) Public constructors and (2) constructor functions are always accessible. - if (!modifiers || declaration.kind !== SyntaxKind.Constructor) { - return true; - } + // (1) Public constructors and (2) constructor functions are always accessible. + if (!modifiers || declaration.kind !== SyntaxKind.Constructor) { + continue; + } - const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(declaration.parent.symbol)!; - const declaringClass = getDeclaredTypeOfSymbol(declaration.parent.symbol) as InterfaceType; + const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(declaration.parent.symbol)!; - // A private or protected constructor can only be instantiated within its own class (or a subclass, for protected) - if (!isNodeWithinClass(node, declaringClassDeclaration)) { - const containingClass = getContainingClass(node); - if (containingClass && modifiers & ModifierFlags.Protected) { - const containingType = getTypeOfNode(containingClass); - if (typeHasProtectedAccessibleBase(declaration.parent.symbol, containingType as InterfaceType)) { - return true; + // A private or protected constructor can only be instantiated within its own class (or a subclass, for protected) + if (!isNodeWithinClass(node, declaringClassDeclaration)) { + const containingClass = getContainingClass(node); + if (containingClass && modifiers & ModifierFlags.Protected) { + const containingType = getTypeOfNode(containingClass); + if (typeHasProtectedAccessibleBase(declaration.parent.symbol, containingType as InterfaceType)) { + continue; + } } + return { + kind: modifiers, + declaringClass: getDeclaredTypeOfSymbol(declaration.parent.symbol), + }; } - if (modifiers & ModifierFlags.Private) { - error(node, Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, typeToString(declaringClass)); - } - if (modifiers & ModifierFlags.Protected) { - error(node, Diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, typeToString(declaringClass)); - } - return false; } - - return true; + return undefined; } function invocationErrorDetails(errorTarget: Node, apparentType: Type, kind: SignatureKind): { messageChain: DiagnosticMessageChain; relatedMessage: DiagnosticMessage | undefined; } { @@ -47349,14 +47352,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkBaseTypeAccessibility(type: Type, node: ExpressionWithTypeArguments) { const signatures = getSignaturesOfType(type, SignatureKind.Construct); - if (signatures.length) { - const declaration = signatures[0].declaration; - if (declaration && hasEffectiveModifier(declaration, ModifierFlags.Private)) { - const typeClassDeclaration = getClassLikeDeclarationOfSymbol(type.symbol)!; - if (!isNodeWithinClass(node, typeClassDeclaration)) { - error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, getFullyQualifiedName(type.symbol)); - } - } + const accessibilityError = getConstructorAccessibilityError(node, signatures, ModifierFlags.Private); + if (accessibilityError) { + error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, getFullyQualifiedName(accessibilityError.declaringClass.symbol)); } } diff --git a/tests/baselines/reference/extendPrivateConstructorClass2.errors.txt b/tests/baselines/reference/extendPrivateConstructorClass2.errors.txt new file mode 100644 index 0000000000000..b8da61049b8c6 --- /dev/null +++ b/tests/baselines/reference/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/tests/baselines/reference/extendPrivateConstructorClass2.symbols b/tests/baselines/reference/extendPrivateConstructorClass2.symbols new file mode 100644 index 0000000000000..08ec1ab380651 --- /dev/null +++ b/tests/baselines/reference/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/tests/baselines/reference/extendPrivateConstructorClass2.types b/tests/baselines/reference/extendPrivateConstructorClass2.types new file mode 100644 index 0000000000000..96c1d3a6654ef --- /dev/null +++ b/tests/baselines/reference/extendPrivateConstructorClass2.types @@ -0,0 +1,399 @@ +//// [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/tests/cases/compiler/extendPrivateConstructorClass2.ts b/tests/cases/compiler/extendPrivateConstructorClass2.ts new file mode 100644 index 0000000000000..22b81c58ca466 --- /dev/null +++ b/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 {} + } +}