fix(parser): avoid TS1477 for parenthesized instantiation expressions#23135
Closed
shawnrice wants to merge 1 commit into
Closed
fix(parser): avoid TS1477 for parenthesized instantiation expressions#23135shawnrice wants to merge 1 commit into
shawnrice wants to merge 1 commit into
Conversation
`(Foo<Bar>).baz` is valid TypeScript but got rejected as TS1477. The check keyed off AST node shape, which only tells it apart from the invalid `Foo<Bar>.baz` when the parens are preserved as a wrapper node. oxfmt and oxlint parse with `preserve_parens: false`, so they hit the false positive. Track whether an instantiation expression was parenthesized in parse state instead, mirroring the existing `not_parenthesized_arrow`. AI usage disclosure: developed with Claude Code, reviewed and tested by me.
graphite-app Bot
pushed a commit
that referenced
this pull request
Jun 9, 2026
…sion (#23147) `oxc_parser` emitted TS1477 ("An instantiation expression cannot be followed by a property access") for parenthesized instantiation expressions such as `(a<b>).c` when `preserve_parens: false` (the mode oxfmt and oxlint use). tsc and Babel accept it — only the *unparenthesized* form is an error. The old check keyed off `lhs` being a `TSInstantiationExpression`, but the `ParenthesizedExpression` wrapper that distinguishes `(a<b>).c` from `a<b>.c` is dropped when `preserve_parens` is off, so the bare instantiation leaked through. ## Fix Emit TS1477 only when the instantiation expression is *not* parenthesized. Instead of relying on a `ParenthesizedExpression` node surviving the AST, detect it by span: an instantiation built in the member-expression loop starts at `lhs_span`, while one unwrapped from a stripped paren starts past the `(`. A shared helper covers both the property-access (`.`) and element-access (`[`) branches. | source | result | notes | | --- | --- | --- | | `a<b>.c` | TS1477 | | | `a<b>?.[c]` | TS1477 | element access on a bare instantiation | | `a?.b<c>.d` | TS1477 | | | `(a<b>).c` | ok | the fix | | `(a<b>)[c]` / `(a<b>)?.[c]` | ok | the fix | | `(a).b<c>.d` | TS1477 | parens wrap `a`, not the instantiation | Correct regardless of `preserve_parens`; under the default (`true`) behavior is unchanged, so no conformance snapshots move. Note: tsc only checks property access (`parsePropertyAccessExpressionRest`), so it does not flag `a<b>?.[c]` — an apparent oversight, since accessing a member of an instantiation expression is the same operation either way. Babel flags both, and this PR keeps oxc's existing behavior for the unparenthesized element-access case. Closes #23133. Alternative to #23135 (same issue, same resulting behavior). That PR records parenthesized instantiation expressions in a new `ParserState` set; this one derives the same fact from spans, needing no extra parser state. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author
camc314
pushed a commit
that referenced
this pull request
Jul 3, 2026
…sion (#23147) `oxc_parser` emitted TS1477 ("An instantiation expression cannot be followed by a property access") for parenthesized instantiation expressions such as `(a<b>).c` when `preserve_parens: false` (the mode oxfmt and oxlint use). tsc and Babel accept it — only the *unparenthesized* form is an error. The old check keyed off `lhs` being a `TSInstantiationExpression`, but the `ParenthesizedExpression` wrapper that distinguishes `(a<b>).c` from `a<b>.c` is dropped when `preserve_parens` is off, so the bare instantiation leaked through. ## Fix Emit TS1477 only when the instantiation expression is *not* parenthesized. Instead of relying on a `ParenthesizedExpression` node surviving the AST, detect it by span: an instantiation built in the member-expression loop starts at `lhs_span`, while one unwrapped from a stripped paren starts past the `(`. A shared helper covers both the property-access (`.`) and element-access (`[`) branches. | source | result | notes | | --- | --- | --- | | `a<b>.c` | TS1477 | | | `a<b>?.[c]` | TS1477 | element access on a bare instantiation | | `a?.b<c>.d` | TS1477 | | | `(a<b>).c` | ok | the fix | | `(a<b>)[c]` / `(a<b>)?.[c]` | ok | the fix | | `(a).b<c>.d` | TS1477 | parens wrap `a`, not the instantiation | Correct regardless of `preserve_parens`; under the default (`true`) behavior is unchanged, so no conformance snapshots move. Note: tsc only checks property access (`parsePropertyAccessExpressionRest`), so it does not flag `a<b>?.[c]` — an apparent oversight, since accessing a member of an instantiation expression is the same operation either way. Babel flags both, and this PR keeps oxc's existing behavior for the unparenthesized element-access case. Closes #23133. Alternative to #23135 (same issue, same resulting behavior). That PR records parenthesized instantiation expressions in a new `ParserState` set; this one derives the same fact from spans, needing no extra parser state. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
(Foo<Bar>).bazis valid TypeScript but got rejected as TS1477, and oxc-parser's behavior diverges from tsc. The check for TS1477 keyed off AST node shape, which only tells it apart from the invalidFoo<Bar>.bazwhen the parens are preserved as a wrapper node. oxfmt parses withpreserve_parens: false, so it hits the false positive.Fix: Track whether an instantiation expression was parenthesized in parse state instead, mirroring the existing
not_parenthesized_arrow.Fixes #23133
AI usage disclosure: developed with Claude Code, reviewed and tested by me.