-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Discriminate contextual types #19733
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
Discriminate contextual types #19733
Conversation
sandersn
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a cool fix! A couple of requests:
src/compiler/checker.ts
Outdated
| return type && getApparentType(type); | ||
| let contextualType = getContextualType(node); | ||
| contextualType = contextualType && getApparentType(contextualType); | ||
| if (contextualType && contextualType.flags & TypeFlags.Union && isObjectLiteralExpression(node)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
invert this I think
src/compiler/checker.ts
Outdated
| contextualType = contextualType && getApparentType(contextualType); | ||
| if (contextualType && contextualType.flags & TypeFlags.Union && isObjectLiteralExpression(node)) { | ||
| let match: Type | undefined; | ||
| propLoop: for (const prop of node.properties) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code is almost exactly the same as the also-highly-questionable findMatchingDiscriminantType. The only real difference, I suspect, is that this code doesn't bail if (type === match). Two things:
- Can you harmonise the two code paths so there's only one
findMatchingDiscriminantType?
2.It's quite possible that the excess-property usage and union-error usage would both benefit from the(type === match)addition, so it could be that you can just swap out the existing body for this code. - Three things! Using
findMatchingDiscriminantTypeis slow, and only makes the compiler faster because it eliminates unions early on. Can you test performance with this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
findMatchingDiscriminantTypeoperates on type members (andfindMatchingDiscriminantTypedirectly usesisRelatedTo), this operates on an actual node tree (as most contextual type operations do), so sadly I don't think they can be merged (without a bunch of inefficient abstractions over weather you're getting symbols from types or nodes and such)- Sure, I'll try modifying
findMatchingDiscriminantType, too; but I don't think it'll show up in much unless we add a test case where multiple fields are capable of acting as a discriminant for an object and discriminate to the same types. 🐱 - Sure, will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh hey, waddoyaknow, we already do have a test (excessPropertyCheckWithUnions) improved by changing findMatchingDiscriminantType. Neat.
|
@sandersn As far as overall perf goes, this has no real effect on any codebase in our perf suite:
|
This was split from #19587, and the idea originated from a comment on #19322 (and then the code moved directly into
getApparentTypeOfContextualTypeinstead ofgetContextualThisParameterTypeso as to be more general), and should be merged after #19587. The primary baseline changes will be visible in tests added in that PR; however there are some small changes already visible here because we toss out uninteresting contextual types earlier based on members we know the type of.This causes a few things:
thistypes are discriminated based on the other members you wrote; meaning methods in objects contextually typed by something now have thethistype of only the discriminated member you've indicated, if possible. (This is the primary benefit the tests in the other PR can show)