-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Infer string literals at comparison locations #6196
Conversation
…, and equality comparisons.
If |
If we do apply a contextual type to |
@@ -10866,7 +10885,7 @@ namespace ts { | |||
} | |||
|
|||
function checkStringLiteralExpression(node: StringLiteral): Type { | |||
const contextualType = getContextualType(node); | |||
const contextualType = getLiteralContextualType(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.
Does this even need to be a type? I mean, do you actually use the type for anything, or just check if it exists? I feel like a boolean is more appropriate.
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.
That actually might be a better way to go about it.
@RyanCavanaugh @weswigham we can discuss that on #6199. |
@JsonFreeman I've separated the logic out. This means we can't do both in the same pass, but ¯_(ツ)_/¯ Does anyone have any thoughts on the current approach to things? |
// In an assignment expression, the right operand is contextually typed by the type of the left operand. | ||
if (node === binaryExpression.right) { | ||
return checkExpression(binaryExpression.left); | ||
} | ||
return undefined; |
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.
Probably don't need this
// a node that isn't a match location, and then get the contextual type of that. | ||
// That would save a few steps but the checks in 'isExpression' seem so involved | ||
// that it would probably be better to simply grab the contextual type if we didn't. | ||
const contextualType = getContextualType(literalNode); |
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.
Why not just pass current
or parent
here?
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.
I guess I assumed too much when I wrote the above comment. getContextualType
expects an Expression
, so we'd need to check if current
is an expression using isExpression
. But that function is so roundabout, I figured we'd be better off just performing the walk from literalNode
again.
Additionally, you need to because we just skipped ||
, where the RHS gets contextually typed by the LHS if a parent contextual type doesn't exist.
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 I see what you mean now about isExpression. And good point about ||
.
I think this change is good. |
This change thinks you're good too Jason. ❤️ |
Thanks for the feedback @ahejlsberg, that really cleaned things up. One issue is that in order to truly state that an expression is an operand in a comparison location, I have to include type assertions. For the most part, this isn't a problem. You shouldn't be able to assert that the type of This might not be a huge deal, but I'd like to hear your thoughts on whether we should make an exception there. |
Will this include intellisense support for string literals (both for assignment and comparison)? Or should I open that as a separate issue. |
@DanielRosenwasser #9407 has now been merged so I think we can close this one. |
closing in favor of #9407 |
This PR removes ad-hoc checks for string-like types by adding new contextual types for literal types at select locations. It addresses some of the major issues brought up in #6167 by adding strictness where users are most interested.
A literal type is inferred for any string literal in a literal match location, defined as such:
switch
statement is a literal match location.case
clause is a literal match location.===
,!==
,==
, or!=
expression is a literal match location.||
expression is a literal match location if the||
expression itself is a literal match location.&&
or,
expression is a literal match location if the&&
or,
expression itself is a literal match location.String literals can still get string literal types through contextual typing, but a check for whether a string is in a literal match location will be apply first.
This means that the following will now error:
because types
"foo"
and"bar"
are not assignable to one another.