From 5ab8bd85aeb280d47c1641c06c30511744b8069b Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 13 Sep 2018 17:49:09 -0700 Subject: [PATCH] Try to find object/intersection types with the most overlap when failing assignability against unions. --- src/compiler/checker.ts | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6f541461b09..9e74fb8521c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11472,7 +11472,8 @@ namespace ts { findMatchingDiscriminantType(source, target) || findMatchingTypeReferenceOrTypeAliasReference(source, target) || findBestTypeForObjectLiteral(source, target) || - findBestTypeForInvokable(source, target); + findBestTypeForInvokable(source, target) || + findMostOverlappyType(source, target); isRelatedTo(source, bestMatchingType || targetTypes[targetTypes.length - 1], /*reportErrors*/ true); } @@ -11512,6 +11513,32 @@ namespace ts { } } + function findMostOverlappyType(source: Type, unionTarget: UnionOrIntersectionType) { + if (!(source.flags & (TypeFlags.Object | TypeFlags.Intersection))) { + return undefined; + } + const sourceProperties = getPropertiesOfType(source); + let bestType; + let count = -1; + for (const target of unionTarget.types) { + if (!(target.flags & (TypeFlags.Object | TypeFlags.Intersection))) { + continue; + } + + let currentCount = 0; + for (const prop of sourceProperties) { + if (getPropertyOfType(target, prop.escapedName)) { + currentCount++; + } + } + if (currentCount >= count) { + count = currentCount; + bestType = target; + } + } + return bestType; + } + // Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly function findMatchingDiscriminantType(source: Type, target: UnionOrIntersectionType) { let match: Type | undefined;