Repository: swc-project/swc (rust)

Issue:
Can't extend type
### Describe the bug

```
Error: error: An interface can only extend an identifier/qualified-name with optional type arguments.
  
   |
58 |   extends ReturnType<typeof mapStateToProps>,
   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```

### Input code

```typescript
interface IConnectedAppProps
  extends ReturnType<typeof mapStateToProps>,
    ReturnType<typeof mapDispatchToProps> {}
```


### Config

_No response_

### Playground link

_No response_

### Expected behavior

No error.

### Actual behavior

_No response_

### Version

1.2.144

### Additional context

_No response_

Pull request:
fix(parser/ts): allow TsInstantiation in extends clause
<!-- Note: CI script will automatically rebase your PR so please do not rebase unless required -->

<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**

<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

**BREAKING CHANGE:**

<!--
If this PR introduces a breaking change, it must contain a notice for it to be included in the CHANGELOG. Add description or remove entirely if not breaking.

You may need to update `MIGRATION.md` for the breaking changes.
-->

**Related issue (if exists):**
- fix #3694 

Patch:
diff --git a/crates/swc_ecma_parser/src/parser/typescript.rs b/crates/swc_ecma_parser/src/parser/typescript.rs
index 18714409b7..155c931c79 100644
--- a/crates/swc_ecma_parser/src/parser/typescript.rs
+++ b/crates/swc_ecma_parser/src/parser/typescript.rs
@@ -938,7 +938,10 @@ impl<I: Tokens> Parser<I> {
 
         let ident = Box::new(Expr::Ident(self.parse_ident_name()?));
         let expr = self.parse_subscripts(Callee::Expr(ident), true, true)?;
-        if !matches!(&*expr, Expr::Ident(..) | Expr::Member(..)) {
+        if !matches!(
+            &*expr,
+            Expr::Ident(..) | Expr::Member(..) | Expr::TsInstantiation(..)
+        ) {
             self.emit_err(span!(self, start), SyntaxError::TS2499);
         }
 


Test patch:
diff --git a/crates/swc/tests/fixture/issue-3694/1/input/.swcrc b/crates/swc/tests/fixture/issue-3694/1/input/.swcrc
new file mode 100644
index 0000000000..0983b8e9f4
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-3694/1/input/.swcrc
@@ -0,0 +1,11 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "typescript"
+        },
+        "target": "es2022"
+    },
+    "module": {
+        "type": "es6"
+    }
+}
diff --git a/crates/swc/tests/fixture/issue-3694/1/input/index.ts b/crates/swc/tests/fixture/issue-3694/1/input/index.ts
new file mode 100644
index 0000000000..4df037cffc
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-3694/1/input/index.ts
@@ -0,0 +1,5 @@
+interface IConnectedAppProps
+    extends ReturnType<typeof mapStateToProps>,
+        ReturnType<typeof mapDispatchToProps> {}
+
+class Foo implements IConnectedAppProps {}
diff --git a/crates/swc/tests/fixture/issue-3694/1/output/index.ts b/crates/swc/tests/fixture/issue-3694/1/output/index.ts
new file mode 100644
index 0000000000..f230fa0f41
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-3694/1/output/index.ts
@@ -0,0 +1,2 @@
+class Foo {
+}
diff --git a/crates/swc_ecma_parser/tests/typescript/issue-3694/input.ts b/crates/swc_ecma_parser/tests/typescript/issue-3694/input.ts
new file mode 100644
index 0000000000..5455a30392
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript/issue-3694/input.ts
@@ -0,0 +1,3 @@
+interface IConnectedAppProps
+    extends ReturnType<typeof mapStateToProps>,
+        ReturnType<typeof mapDispatchToProps> {}
diff --git a/crates/swc_ecma_parser/tests/typescript/issue-3694/input.ts.json b/crates/swc_ecma_parser/tests/typescript/issue-3694/input.ts.json
new file mode 100644
index 0000000000..90f254a939
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript/issue-3694/input.ts.json
@@ -0,0 +1,136 @@
+{
+  "type": "Script",
+  "span": {
+    "start": 0,
+    "end": 125,
+    "ctxt": 0
+  },
+  "body": [
+    {
+      "type": "TsInterfaceDeclaration",
+      "span": {
+        "start": 0,
+        "end": 125,
+        "ctxt": 0
+      },
+      "id": {
+        "type": "Identifier",
+        "span": {
+          "start": 10,
+          "end": 28,
+          "ctxt": 0
+        },
+        "value": "IConnectedAppProps",
+        "optional": false
+      },
+      "declare": false,
+      "typeParams": null,
+      "extends": [
+        {
+          "type": "TsExpressionWithTypeArguments",
+          "span": {
+            "start": 41,
+            "end": 75,
+            "ctxt": 0
+          },
+          "expression": {
+            "type": "Identifier",
+            "span": {
+              "start": 41,
+              "end": 51,
+              "ctxt": 0
+            },
+            "value": "ReturnType",
+            "optional": false
+          },
+          "typeArguments": {
+            "type": "TsTypeParameterInstantiation",
+            "span": {
+              "start": 51,
+              "end": 75,
+              "ctxt": 0
+            },
+            "params": [
+              {
+                "type": "TsTypeQuery",
+                "span": {
+                  "start": 52,
+                  "end": 74,
+                  "ctxt": 0
+                },
+                "exprName": {
+                  "type": "Identifier",
+                  "span": {
+                    "start": 59,
+                    "end": 74,
+                    "ctxt": 0
+                  },
+                  "value": "mapStateToProps",
+                  "optional": false
+                },
+                "typeArguments": null
+              }
+            ]
+          }
+        },
+        {
+          "type": "TsExpressionWithTypeArguments",
+          "span": {
+            "start": 85,
+            "end": 122,
+            "ctxt": 0
+          },
+          "expression": {
+            "type": "Identifier",
+            "span": {
+              "start": 85,
+              "end": 95,
+              "ctxt": 0
+            },
+            "value": "ReturnType",
+            "optional": false
+          },
+          "typeArguments": {
+            "type": "TsTypeParameterInstantiation",
+            "span": {
+              "start": 95,
+              "end": 122,
+              "ctxt": 0
+            },
+            "params": [
+              {
+                "type": "TsTypeQuery",
+                "span": {
+                  "start": 96,
+                  "end": 121,
+                  "ctxt": 0
+                },
+                "exprName": {
+                  "type": "Identifier",
+                  "span": {
+                    "start": 103,
+                    "end": 121,
+                    "ctxt": 0
+                  },
+                  "value": "mapDispatchToProps",
+                  "optional": false
+                },
+                "typeArguments": null
+              }
+            ]
+          }
+        }
+      ],
+      "body": {
+        "type": "TsInterfaceBody",
+        "span": {
+          "start": 123,
+          "end": 125,
+          "ctxt": 0
+        },
+        "body": []
+      }
+    }
+  ],
+  "interpreter": null
+}