Use intersection of member names to find largest overlap.

This commit is contained in:
Daniel Rosenwasser 2018-11-16 15:59:00 -08:00
parent 646e234f88
commit 06fe1ed537

View File

@ -11963,29 +11963,31 @@ 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;
let bestMatch: Type | undefined;
let matchingCount = 0;
for (const target of unionTarget.types) {
if (!(target.flags & (TypeFlags.Object | TypeFlags.Intersection))) {
continue;
const overlap = getIntersectionType([getIndexType(source), getIndexType(target)]);
if (overlap.flags & TypeFlags.Index) {
// perfect overlap of keys
bestMatch = target;
matchingCount = Infinity;
}
let currentCount = 0;
for (const prop of sourceProperties) {
if (getPropertyOfType(target, prop.escapedName)) {
currentCount++;
else if (overlap.flags & TypeFlags.Union) {
// Some subset overlap if we have only string literals.
// If we have a union of index types, it seems likely that we
// needed to elaborate between two generic mapped types anyway.
const len = length((overlap as UnionType).types);
if (len >= matchingCount) {
bestMatch = target;
matchingCount = len;
}
}
if (currentCount >= count) {
count = currentCount;
bestType = target;
else if (!(overlap.flags & TypeFlags.Never) && 1 >= matchingCount) {
bestMatch = target;
matchingCount = 1;
}
}
return bestType;
return bestMatch;
}
// Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly