-
Notifications
You must be signed in to change notification settings - Fork 12.3k
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
type
identifier should not trigger an parsing error when part of an assertion
#58712
base: main
Are you sure you want to change the base?
Conversation
…ing error when part of an assertion
Also, considering |
Oops, indeed. |
type
identifier should not trigger an parsing error when part of an assertion
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.
The more I think about it, I realized this is a bit of a tricky problem because the look-ahead is unbounded. You can write
type satisfies <T>() => T
And from the parser's point of view, when it sees
type satisfies <
it needs to make a call of whether this is going to be a type alias or a satisfies
expression.
So what I would do is keep the special-casing for as
and satisfies
and make sure we have tests for things like
// These were written with the expectation of parse errors.
// We expect the parser to try constructing a statement expression
// with 'satisfies' and 'as' expressions.
type satisfies<T> = T;
type as<T> = T;
and
// These should be parsed as statements
// with 'satisfies' and 'as' expressions.
type satisfies <T>() => T;
type as <T>() => T;
src/compiler/parser.ts
Outdated
} | ||
|
||
switch (token()) { | ||
case SyntaxKind.AsKeyword: |
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.
It really feels like this function should have been left as-is, and the look-ahead should have been done after calling this function specifically for the type
keyword.
It also might be the case that you don't actually need to special-case as
and satisfies
, you can just do an unconditional look-ahead. But I might have to think about that.
src/compiler/parser.ts
Outdated
switch (token()) { | ||
case SyntaxKind.AsKeyword: | ||
case SyntaxKind.SatisfiesKeyword: { | ||
return lookAhead(() => nextToken() === SyntaxKind.EqualsToken); |
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.
The name of a type alias isn't always immediately followed by an =
, so I don't think this specific look-ahead is enough.
See the comment I'm leaving in my review.
type satisfies<T> = T;
Also, like @whzx5byb mentioned, you should add an |
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 hope I understand what you have in mind.
I've left comments to make it clear what I understand needs to be done.
~~~~~~ | ||
!!! error TS1005: '{' expected. | ||
~~~~~~ | ||
!!! error TS2693: 'string' only refers to a type, but is being used as a value 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.
Make sure there are no regressions concerning the interface
keyword.
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.
Can you explicitly test interface satisfies { }
?
@@ -0,0 +1,2 @@ | |||
type satisfies<T> = T; | |||
type as<T> = T; |
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.
Type parameters were not parsed.
This test ensures these are considered type aliases.
const type = <T,>(x: T) => x; | ||
|
||
type satisfies <T>(x: T) => T; | ||
type as <T>() => T; |
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.
Make sure that assertions with type parameters are parsed as assertions.
return nextTokenIsIdentifierOnSameLine(); | ||
case SyntaxKind.TypeKeyword: | ||
const isIdentifierOnSameLine = nextTokenIsIdentifierOnSameLine(); | ||
if (isIdentifierOnSameLine && token() === SyntaxKind.AsKeyword || token() === SyntaxKind.SatisfiesKeyword) { |
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.
Do you think this part should be in a proper function?
We could return something like this:
return nextTokenIsIdentifierOnSameLine() && someNameToExplainsWhatIsDoneRegardingSatisfiesAndAs()
if (isIdentifierOnSameLine && token() === SyntaxKind.AsKeyword || token() === SyntaxKind.SatisfiesKeyword) { | ||
return lookAhead(() => { | ||
nextToken(); | ||
parseTypeParameters(); |
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 feels like it would be pretty wasteful, but I suppose that people can't write this code today anyway and it'd only be paid for as
and satisfies
.
Will fixes #58248
I'm not sure if there are any other cases I've missed. I'll take a closer look this week, but feel free to give feedbacks 🙏
This should be ok: