Skip to content

Commit f06d3f6

Browse files
committed
Only narrow to {} in getNarrowedType when types are completely unrelated
1 parent 4fb31ac commit f06d3f6

1 file changed

Lines changed: 19 additions & 33 deletions

File tree

src/compiler/checker.ts

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7327,18 +7327,6 @@ namespace ts {
73277327
return false;
73287328
}
73297329

7330-
function typeMaybeSubtypeOf(source: Type, target: Type) {
7331-
if (!(source.flags & TypeFlags.Union)) {
7332-
return isTypeSubtypeOf(source, target);
7333-
}
7334-
for (const t of (<UnionType>source).types) {
7335-
if (isTypeSubtypeOf(t, target)) {
7336-
return true;
7337-
}
7338-
}
7339-
return false;
7340-
}
7341-
73427330
// Remove those constituent types of declaredType to which no constituent type of assignedType is assignable.
73437331
// For example, when a variable of type number | string | boolean is assigned a value of type number | boolean,
73447332
// we remove type string.
@@ -7769,28 +7757,26 @@ namespace ts {
77697757
}
77707758

77717759
function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean) {
7772-
if (typeMaybeSubtypeOf(type, candidate)) {
7773-
// If the current type, or a constituent of the current type, is a subtype of
7774-
// the candidate type then the current type contains the most specific information.
7775-
// and we simply filter out constituents that aren't applicable. For example,
7776-
// if the current type is string | string[] and the candidate type is any[],
7777-
// we filter out string.
7760+
if (!assumeTrue) {
77787761
return type.flags & TypeFlags.Union ?
7779-
getUnionType(filter((<UnionType>type).types, t => isTypeSubtypeOf(t, candidate) === assumeTrue)) :
7780-
assumeTrue ? type : emptyUnionType;
7781-
}
7782-
if (assumeTrue) {
7783-
// In the true branch of the remaining cases, if the candidate type is assignable
7784-
// to the current type, then we narrow to the candidate type. Otherwise, we narrow
7785-
// to an empty type (because we now know the types are completely unrelated). For
7786-
// example, if the current type is Object and the candidate type is string[], we
7787-
// narrow to string[]. But if the current type is string and the candidate is
7788-
// string[], we narrow to the empty type.
7789-
const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type;
7790-
return isTypeAssignableTo(candidate, targetType) ? candidate : emptyUnionType;
7791-
}
7792-
// In the false branch of the remaining cases we leave the type unchanged.
7793-
return type;
7762+
getUnionType(filter((<UnionType>type).types, t => !isTypeSubtypeOf(t, candidate))) :
7763+
type;
7764+
}
7765+
// If the current type is a union type, remove all constituents that aren't assignable to
7766+
// the candidate type. If one or more constituents remain, return a union of those.
7767+
if (type.flags & TypeFlags.Union) {
7768+
const assignableConstituents = filter((<UnionType>type).types, t => isTypeAssignableTo(t, candidate));
7769+
if (assignableConstituents.length) {
7770+
return getUnionType(assignableConstituents);
7771+
}
7772+
}
7773+
// If the candidate type is assignable to the target type, narrow to the candidate type.
7774+
// Otherwise, if the current type is assignable to the candidate, keep the current type.
7775+
// Otherwise, the types are completely unrelated, so narrow to the empty type.
7776+
const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type;
7777+
return isTypeAssignableTo(candidate, targetType) ? candidate :
7778+
isTypeAssignableTo(type, candidate) ? type :
7779+
emptyUnionType;
77947780
}
77957781

77967782
function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type {

0 commit comments

Comments
 (0)