Skip to content

Commit e85971c

Browse files
committed
Optimize for discriminated unions
1 parent 37bfa91 commit e85971c

File tree

1 file changed

+17
-11
lines changed

1 file changed

+17
-11
lines changed

src/compiler/checker.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25318,19 +25318,25 @@ namespace ts {
2531825318
if (!assumeTrue) {
2531925319
return filterType(type, t => !isRelated(t, candidate));
2532025320
}
25321+
if (type.flags & TypeFlags.AnyOrUnknown) {
25322+
return candidate;
25323+
}
2532125324
// We first attempt to filter the current type, narrowing constituents as appropriate and removing
2532225325
// constituents that are unrelated to the candidate.
25323-
const narrowedType = type.flags & TypeFlags.AnyOrUnknown ? candidate :
25324-
mapType(candidate, c => {
25325-
// For each constituent t in the current type, if t and and c are directly related, pick the most
25326-
// specific of the two.
25327-
const directlyRelated = mapType(type, t => isRelated(t, c) ? t : isRelated(c, t) ? c : neverType);
25328-
// If no constituents are directly related, create intersections for any generic constituents that
25329-
// are related by constraint.
25330-
return directlyRelated.flags & TypeFlags.Never ?
25331-
mapType(type, t => maybeTypeOfKind(t, TypeFlags.Instantiable) && isRelated(c, getBaseConstraintOfType(t) || unknownType) ? getIntersectionType([t, c]) : neverType) :
25332-
directlyRelated;
25333-
});
25326+
const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined;
25327+
const narrowedType = mapType(candidate, c => {
25328+
// If a discriminant property is available, use that to reduce the type.
25329+
const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName);
25330+
const matching = discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant);
25331+
// For each constituent t in the current type, if t and and c are directly related, pick the most
25332+
// specific of the two.
25333+
const directlyRelated = mapType(matching || type, t => isRelated(t, c) ? t : isRelated(c, t) ? c : neverType);
25334+
// If no constituents are directly related, create intersections for any generic constituents that
25335+
// are related by constraint.
25336+
return directlyRelated.flags & TypeFlags.Never ?
25337+
mapType(type, t => maybeTypeOfKind(t, TypeFlags.Instantiable) && isRelated(c, getBaseConstraintOfType(t) || unknownType) ? getIntersectionType([t, c]) : neverType) :
25338+
directlyRelated;
25339+
});
2533425340
// If filtering produced a non-empty type, return that. Otherwise, pick the most specific of the two
2533525341
// based on assignability, or as a last resort produce an intersection.
2533625342
return !(narrowedType.flags & TypeFlags.Never) ? narrowedType :

0 commit comments

Comments
 (0)