-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistent narrowing from unions with overlapping possibly-optional properties #26551
Comments
This is the relevant code // If the current type is a union type, remove all constituents that couldn't be instances of
// the candidate type. If one or more constituents remain, return a union of those.
if (type.flags & TypeFlags.Union) {
const assignableType = filterType(type, t => isRelated(t, candidate));
if (!(assignableType.flags & TypeFlags.Never)) {
return assignableType;
}
}
// If the candidate type is a subtype of the target type, narrow to the candidate type.
// Otherwise, if the target type is assignable to the candidate type, keep the target type.
// Otherwise, if the candidate type is assignable to the target type, narrow to the candidate
// type. Otherwise, the types are completely unrelated, so narrow to an intersection of the
// two types.
return isTypeSubtypeOf(candidate, type) ? candidate :
isTypeAssignableTo(type, candidate) ? type :
isTypeAssignableTo(candidate, type) ? candidate :
getIntersectionType([type, candidate]); Basically, unions and non-unions narrow differently. For a union, we remove non-assignable constituents; for a non-union, we intersect in the guarded type if it's disjoint from the original type. This generally produces the best behavior in both cases, at the cost of creating an "inconsistency" |
Thanks. I guess I don't see how |
|
Ah, okay. |
TypeScript Version: 3.1.0-dev.20180813
Search Terms:
type guard, narrowing, union, optional, overlapping
Code
Expected behavior:
With
--strictNullChecks
on: after being narrowed by the type guard, bothx.a
andy.a
should bestring | undefined
.Actual behavior:
The type guard narrows
y
to{a: string}
for some reason. The{a?: string}
constituent is presumably being eliminated from the union, but I'm not sure why.Playground Link:
Link
Related Issues:
Didn't find anything obvious... maybe #11403 or #17561?
Noticed in a comment in #21732.
The text was updated successfully, but these errors were encountered: