Repository: babel/babel (TypeScript)

Issue:
[Bug]: `x < y >= z` is incorrectly considered an assignment expression in TypeScript
### 💻

- [ ] Would you like to work on a fix?

### How are you using Babel?

Other (Next.js, Gatsby, vue-cli, ...)

### Input code

```ts
fn(x < y, x >= y)
```

REPL: [link](https://babel.dev/repl#?browsers=&code_lz=GYOwFAHgBAPFCeAaK0B8BeBBKAUEA&presets=env%2Ctypescript&version=7.21.8)


### Configuration file name

_No response_

### Configuration

_No response_

### Current and expected behavior

When this TypeScript code is transformed into JavaScript by Babel, Babel fails with the following error:

```
/repl.ts: Invalid left-hand side in assignment expression. (1:3)

> 1 | fn(x < y, x >= y)
    |    ^
  2 |
```

The official TypeScript compiler succeeds with the following output instead:

```js
fn(x < y, x >= y);
```


### Environment

(I only ran Babel via the REPL)

### Possible solution

Here's what I discovered when I fixed this for esbuild: TypeScript's `parseTypeArgumentsInExpression` function backtracks unless the trailing `>` comes from a `>` real token. This is subtle because TypeScript's type argument parser normally strips off the leading `>` from a token, which is why `>>` works in `a<b<c>>(d)`. But it turns out that should only be done when you're in a type context. When you're in an expression context, the trailing `>` must not come from a token that has anything else after it. So for example `a<b<c>>=(d)` should not be considered a type argument list because `parseTypeArgumentsInExpression` encounters a `>=` token.


### Additional context

I just fixed this bug in esbuild: https://github.com/evanw/esbuild/issues/3111. I'm reporting it here because Babel appears to have a similar issue.



Hints:
Hey @evanw! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant [Slack community](https://babeljs.slack.com) that typically always has someone willing to help. You can sign-up [here](https://slack.babeljs.io/) for an invite.

Patch:
diff --git a/packages/babel-parser/src/plugins/typescript/index.ts b/packages/babel-parser/src/plugins/typescript/index.ts
--- a/packages/babel-parser/src/plugins/typescript/index.ts
+++ b/packages/babel-parser/src/plugins/typescript/index.ts
@@ -2281,6 +2281,10 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
       );
       if (node.params.length === 0) {
         this.raise(TSErrors.EmptyTypeArguments, { at: node });
+      } else if (!this.state.inType && this.curContext() === tc.brace) {
+        // rescan `>` when we are no longer in type context and JSX parsing context
+        // since it was tokenized when `inType` is `true`.
+        this.reScan_lt_gt();
       }
       this.expect(tt.gt);
       return this.finishNode(node, "TSTypeParameterInstantiation");


Test patch:
diff --git a/packages/babel-parser/test/fixtures/typescript/type-arguments/instantiation-expression-false-positive-5/input.ts b/packages/babel-parser/test/fixtures/typescript/type-arguments/instantiation-expression-false-positive-5/input.ts
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/typescript/type-arguments/instantiation-expression-false-positive-5/input.ts
@@ -0,0 +1 @@
+fn(x < y, x >= y)
diff --git a/packages/babel-parser/test/fixtures/typescript/type-arguments/instantiation-expression-false-positive-5/output.json b/packages/babel-parser/test/fixtures/typescript/type-arguments/instantiation-expression-false-positive-5/output.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/typescript/type-arguments/instantiation-expression-false-positive-5/output.json
@@ -0,0 +1,58 @@
+{
+  "type": "File",
+  "start":0,"end":17,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":17,"index":17}},
+  "program": {
+    "type": "Program",
+    "start":0,"end":17,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":17,"index":17}},
+    "sourceType": "module",
+    "interpreter": null,
+    "body": [
+      {
+        "type": "ExpressionStatement",
+        "start":0,"end":17,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":17,"index":17}},
+        "expression": {
+          "type": "CallExpression",
+          "start":0,"end":17,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":17,"index":17}},
+          "callee": {
+            "type": "Identifier",
+            "start":0,"end":2,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":2,"index":2},"identifierName":"fn"},
+            "name": "fn"
+          },
+          "arguments": [
+            {
+              "type": "BinaryExpression",
+              "start":3,"end":8,"loc":{"start":{"line":1,"column":3,"index":3},"end":{"line":1,"column":8,"index":8}},
+              "left": {
+                "type": "Identifier",
+                "start":3,"end":4,"loc":{"start":{"line":1,"column":3,"index":3},"end":{"line":1,"column":4,"index":4},"identifierName":"x"},
+                "name": "x"
+              },
+              "operator": "<",
+              "right": {
+                "type": "Identifier",
+                "start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"y"},
+                "name": "y"
+              }
+            },
+            {
+              "type": "BinaryExpression",
+              "start":10,"end":16,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":16,"index":16}},
+              "left": {
+                "type": "Identifier",
+                "start":10,"end":11,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":11,"index":11},"identifierName":"x"},
+                "name": "x"
+              },
+              "operator": ">=",
+              "right": {
+                "type": "Identifier",
+                "start":15,"end":16,"loc":{"start":{"line":1,"column":15,"index":15},"end":{"line":1,"column":16,"index":16},"identifierName":"y"},
+                "name": "y"
+              }
+            }
+          ]
+        }
+      }
+    ],
+    "directives": []
+  }
+}