@@ -25405,23 +25405,32 @@ namespace ts {
2540525405 if (!assumeTrue) {
2540625406 return filterType(type, t => !isRelated(t, candidate));
2540725407 }
25408- // If the current type is a union type, remove all constituents that couldn't be instances of
25409- // the candidate type. If one or more constituents remain, return a union of those.
25410- if (type.flags & TypeFlags.Union) {
25411- const assignableType = filterType(type, t => isRelated(t, candidate));
25412- if (!(assignableType.flags & TypeFlags.Never)) {
25413- return assignableType;
25414- }
25415- }
25416- // If the candidate type is a subtype of the target type, narrow to the candidate type.
25417- // Otherwise, if the target type is assignable to the candidate type, keep the target type.
25418- // Otherwise, if the candidate type is assignable to the target type, narrow to the candidate
25419- // type. Otherwise, the types are completely unrelated, so narrow to an intersection of the
25420- // two types.
25421- return isTypeSubtypeOf(candidate, type) ? candidate :
25422- isTypeAssignableTo(type, candidate) ? type :
25423- isTypeAssignableTo(candidate, type) ? candidate :
25424- getIntersectionType([type, candidate]);
25408+ if (type.flags & TypeFlags.AnyOrUnknown) {
25409+ return candidate;
25410+ }
25411+ // We first attempt to filter the current type, narrowing constituents as appropriate and removing
25412+ // constituents that are unrelated to the candidate.
25413+ const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined;
25414+ const narrowedType = mapType(candidate, c => {
25415+ // If a discriminant property is available, use that to reduce the type.
25416+ const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName);
25417+ const matching = discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant);
25418+ // For each constituent t in the current type, if t and and c are directly related, pick the most
25419+ // specific of the two.
25420+ const directlyRelated = mapType(matching || type, t => isRelated(t, c) ? t : isRelated(c, t) ? c : neverType);
25421+ // If no constituents are directly related, create intersections for any generic constituents that
25422+ // are related by constraint.
25423+ return directlyRelated.flags & TypeFlags.Never ?
25424+ mapType(type, t => maybeTypeOfKind(t, TypeFlags.Instantiable) && isRelated(c, getBaseConstraintOfType(t) || unknownType) ? getIntersectionType([t, c]) : neverType) :
25425+ directlyRelated;
25426+ });
25427+ // If filtering produced a non-empty type, return that. Otherwise, pick the most specific of the two
25428+ // based on assignability, or as a last resort produce an intersection.
25429+ return !(narrowedType.flags & TypeFlags.Never) ? narrowedType :
25430+ isTypeSubtypeOf(candidate, type) ? candidate :
25431+ isTypeAssignableTo(type, candidate) ? type :
25432+ isTypeAssignableTo(candidate, type) ? candidate :
25433+ getIntersectionType([type, candidate]);
2542525434 }
2542625435
2542725436 function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type {
0 commit comments