Skip to content

Conversation

@steffen-heil-secforge
Copy link

Description:

After type assertions (as) and satisfies expressions, the parser needs to determine whether a following < token is a comparison operator or the start of type parameters. This fix ensures that < is lexed as a comparison operator when the type cannot have type parameters.

Previously only primitive keyword types and literals were handled. This extends the logic to cover all non-callable type constructs:

  • Primitive keyword types (number, string, boolean, etc.)
  • Literal types (2, "x", true, 10n)
  • this type
  • Array types (number[], Array)
  • Tuple types ([number, string])
  • Union/intersection types (A | B, A & B)
  • Type operators (keyof T, readonly T, unique symbol)
  • Indexed access types (T[K])
  • Conditional types (T extends U ? X : Y)
  • Mapped types ({ [K in keyof T]: V })
  • Type predicates (x is string)

This prevents parsing errors when these type assertions are followed by comparison operators.

Examples that now parse correctly:

  • (i as number[]) < 5
  • (i as [number, string]) < 5
  • (i as number | string) < 5
  • (i as keyof T) < 5

…ary expressions

After type assertions (`as`) and satisfies expressions, the parser needs to
determine whether a following `<` token is a comparison operator or the start
of type parameters. This fix ensures that `<` is lexed as a comparison operator
when the type cannot have type parameters.

Previously only primitive keyword types and literals were handled. This extends
the logic to cover all non-callable type constructs:
- Primitive keyword types (number, string, boolean, etc.)
- Literal types (2, "x", true, 10n)
- this type
- Array types (number[], Array<number>)
- Tuple types ([number, string])
- Union/intersection types (A | B, A & B)
- Type operators (keyof T, readonly T, unique symbol)
- Indexed access types (T[K])
- Conditional types (T extends U ? X : Y)
- Mapped types ({ [K in keyof T]: V })
- Type predicates (x is string)

This prevents parsing errors when these type assertions are followed by
comparison operators.

Examples that now parse correctly:
- (i as number[]) < 5
- (i as [number, string]) < 5
- (i as number | string) < 5
- (i as keyof T) < 5

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@steffen-heil-secforge steffen-heil-secforge requested a review from a team as a code owner November 9, 2025 12:44
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@changeset-bot
Copy link

changeset-bot bot commented Nov 9, 2025

⚠️ No Changeset found

Latest commit: e18227b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 9, 2025

Binary Sizes

File Size
swc.linux-x64-gnu.node 31M (31910408 bytes)

Commit: 64a931a

@codspeed-hq
Copy link

codspeed-hq bot commented Nov 9, 2025

CodSpeed Performance Report

Merging #11251 will not alter performance

Comparing secforge:fix/type-assertion-disambiguation (e18227b) with main (d66dab5)1

Summary

✅ 138 untouched

Footnotes

  1. No successful run was found on main (527c391) during the generation of this report, so d66dab5 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@CPunisher
Copy link
Member

Could do please provide an example with https://play.swc.rs/ to show the parsing errors?

@steffen-heil-secforge
Copy link
Author

Note, I will update the tests shortly

steffen-heil-secforge and others added 2 commits November 9, 2025 15:14
Only test files were modified to verify the type assertion handling behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@steffen-heil-secforge
Copy link
Author

The point is that there is no explicit bug in swc alone.
From the POV of swc this is just an optimization, because >= and <= are "merged" later in the parser code.
However, dprints typescript plugin uses swc internally and sees the unmerged tokens and then panics.
This patch prevents reading <= and >= (and others) incorrectly in the first place, maybe even making the merge login in the parser redundant. But I wanted to keep the change minimal.

Examples of dprint typescript failing because of this:
https://dprint.dev/playground/#code/JYAghgziB2CuC2AjApgJxAHgLwgKwG4BYAKCA/plugin/typescript
https://dprint.dev/playground/#code/JYAghgziAaA8CaA+EsC8ICsBuAsAKCA/plugin/typescript

@kdy1
Copy link
Member

kdy1 commented Nov 9, 2025

I don't think it's a bug of the ES parser. You added tests to a wrong place, meaning that it was already working

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants