diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6a65743b648..25e763a7277 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5090,30 +5090,21 @@ namespace ts { let result = Ternary.True; let saveErrorInfo = errorInfo; - // Because the "abstractness" of a class is the same across all construct signatures - // (internally we are checking the corresponding declaration), it is enough to perform - // the check and report an error once over all pairs of source and target construct signatures. - let sourceSig = sourceSignatures[0]; - // Note that in an extends-clause, targetSignatures is stripped, so the check never proceeds. - let targetSig = targetSignatures[0]; - if (sourceSig && targetSig) { - let sourceErasedSignature = getErasedSignature(sourceSig); - let targetErasedSignature = getErasedSignature(targetSig); - let sourceReturnType = sourceErasedSignature && getReturnTypeOfSignature(sourceErasedSignature); - let targetReturnType = targetErasedSignature && getReturnTypeOfSignature(targetErasedSignature); + if (kind === SignatureKind.Construct) { + // Only want to compare the construct signatures for abstractness guarantees. + + // Because the "abstractness" of a class is the same across all construct signatures + // (internally we are checking the corresponding declaration), it is enough to perform + // the check and report an error once over all pairs of source and target construct signatures. + let sourceSig = sourceSignatures[0]; + // Note that in an extends-clause, targetSignatures is stripped, so the check never proceeds. + let targetSig = targetSignatures[0]; - let sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration); - let targetReturnDecl = targetReturnType && targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); - let sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract; - let targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract; - - if (sourceIsAbstract && !targetIsAbstract) { - if (reportErrors) { - reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); - } - return Ternary.False; + result &= abstractSignatureRelatedTo(source, sourceSig, target, targetSig); + if (result !== Ternary.True) { + return result; } } @@ -5137,6 +5128,40 @@ namespace ts { } } return result; + + function abstractSignatureRelatedTo(source: Type, sourceSig: Signature, target: Type, targetSig: Signature) { + if (sourceSig && targetSig) { + + let sourceDecl = getDeclarationOfKind(source.symbol, SyntaxKind.ClassDeclaration); + let targetDecl = getDeclarationOfKind(target.symbol, SyntaxKind.ClassDeclaration); + + if (!sourceDecl) { + // If the source object isn't itself a class declaration, it can be freely assigned, regardless + // of whether the constructed object is abstract or not. + return Ternary.True; + } + + let sourceErasedSignature = getErasedSignature(sourceSig); + let targetErasedSignature = getErasedSignature(targetSig); + + let sourceReturnType = sourceErasedSignature && getReturnTypeOfSignature(sourceErasedSignature); + let targetReturnType = targetErasedSignature && getReturnTypeOfSignature(targetErasedSignature); + + let sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration); + let targetReturnDecl = targetReturnType && targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration); + let sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract; + let targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & NodeFlags.Abstract; + + // abstract constructor functions are only + if (sourceIsAbstract && !(targetIsAbstract && targetDecl)) { + if (reportErrors) { + reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); + } + return Ternary.False; + } + } + return Ternary.True; + } } function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index da43984ee13..d19ed62332e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1786,10 +1786,10 @@ namespace ts { ObjectType = Class | Interface | Reference | Tuple | Anonymous, UnionOrIntersection = Union | Intersection, StructuredType = ObjectType | Union | Intersection, - /* @internal */ + /* @internal */ RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral, /* @internal */ - PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType + PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType } // Properties common to all types