Skip to content
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

Allow filterType to consider union constraints of non-union types when determining never-ness #43763

Merged
merged 4 commits into from
May 5, 2021

Conversation

weswigham
Copy link
Member

Fixes #43719

Normally, in narrowing, we combine the true and false branch flow types, and that didn't appear to occur in the linked issue. In reality, it was happening exactly as specified - the false branch type was simply never because for the false branch we'd check if Slices[SliceId][SliceKey] is a subtype of NumClass<number>, which it obviously is not (after all, it's constrained to NumClass<number> | StrClass<string>, which is a supertype of it). The solution is, in the false case, allowing filterType to break the type into it's constraint and see if any component of the constraint fits the bill when checking validity, since what we really want to know is if any part of the filtered type isn't a subtype of the type we're narrowing by.

@typescript-bot typescript-bot added the For Milestone Bug PRs that fix a bug with a specific milestone label Apr 21, 2021
@@ -23732,7 +23732,7 @@ namespace ts {

function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, isRelated: (source: Type, target: Type) => boolean) {
if (!assumeTrue) {
return filterType(type, t => !isRelated(t, candidate));
return filterType(type, t => !isRelated(t, candidate), /*checkConstraints*/ true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you anticipate this parameter being useful outside this one call? Why not just put the constraint-checking code in this one callback?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you anticipate this parameter being useful outside this one call?

OK, so, get this: I removed this flag and made filterType unconditionally break apart constraints. We use filterType all over - surely this would make something fail in a case where, eg, we're looking for nullable types and start returning arbitrary Ts constrained to nullable types. Surely that would cause a test to fail. And yet, it did not. And this was spooky - is our coverage of the different ways we filter types really so poor? So I kept the flag, not wanting to accidentally break other usages of the filterType call that maybe did not expect the constraint decomposition when they were written, but are just poorly covered by tests.

Why not just put the constraint-checking code in this one callback?

I guess I could! It'd arguably be more consistent then, especially since it'd cause the constraint breakdown to be recursively invoked on unions whose members are type variables.

@andrewbranch
Copy link
Member

Is the self-build error an actual result of the change to getNarrowedType? 😮

@weswigham
Copy link
Member Author

Yep.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Milestone Bug PRs that fix a bug with a specific milestone
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Custom type guard / generic predicate leaks outside its scope in certain settings
4 participants