Repository: swc-project/swc (rust)

Issue:
TsConstructSignatureDecl type_params is not output
### Describe the bug

The type specified by type_params of TsConstructSignatureDecl is not output in swc_ecma_codegen

### Input code

```typescript
#[test]
fn output_construct_signature_with_type_params() {
    let type_parameter_t_ident =
        swc_ecma_ast::Ident::new(string_cache::Atom::from("T"), swc_common::Span::default());
    let type_decl = swc_ecma_ast::TsTypeLit {
        span: swc_common::Span::default(),
        members: vec![swc_ecma_ast::TsTypeElement::TsConstructSignatureDecl(
            swc_ecma_ast::TsConstructSignatureDecl {
                span: swc_common::Span::default(),
                params: vec![swc_ecma_ast::TsFnParam::Ident(swc_ecma_ast::BindingIdent {
                    id: swc_ecma_ast::Ident::new(
                        string_cache::Atom::from("value"),
                        swc_common::Span::default(),
                    ),
                    type_ann: Some(Box::new(swc_ecma_ast::TsTypeAnn {
                        span: swc_common::Span::default(),
                        type_ann: Box::new(swc_ecma_ast::TsType::TsTypeRef(
                            swc_ecma_ast::TsTypeRef {
                                span: swc_common::Span::default(),
                                type_name: swc_ecma_ast::TsEntityName::Ident(
                                    type_parameter_t_ident.clone(),
                                ),
                                type_params: None,
                            },
                        )),
                    })),
                })],
                type_ann: Some(Box::new(swc_ecma_ast::TsTypeAnn {
                    span: swc_common::Span::default(),
                    type_ann: Box::new(swc_ecma_ast::TsType::TsTypeRef(swc_ecma_ast::TsTypeRef {
                        span: swc_common::Span::default(),
                        type_name: swc_ecma_ast::TsEntityName::Ident(swc_ecma_ast::Ident::new(
                            string_cache::Atom::from("Obj"),
                            swc_common::Span::default(),
                        )),
                        type_params: Some(Box::new(swc_ecma_ast::TsTypeParamInstantiation {
                            span: swc_common::Span::default(),
                            params: vec![Box::new(swc_ecma_ast::TsType::TsTypeRef(
                                swc_ecma_ast::TsTypeRef {
                                    span: swc_common::Span::default(),
                                    type_name: swc_ecma_ast::TsEntityName::Ident(
                                        type_parameter_t_ident.clone(),
                                    ),
                                    type_params: None,
                                },
                            ))],
                        })),
                    })),
                })),
                // ignored ?
                type_params: Some(Box::new(swc_ecma_ast::TsTypeParamDecl {
                    span: swc_common::Span::default(),
                    params: vec![swc_ecma_ast::TsTypeParam {
                        span: swc_common::Span::default(),
                        name: type_parameter_t_ident.clone(),
                        is_in: false,
                        is_out: false,
                        is_const: false,
                        constraint: None,
                        default: None,
                    }],
                })),
            },
        )],
    };

    let cm = swc_common::sync::Lrc::<swc_common::SourceMap>::default();
    let mut buf = vec![];
    let writer = swc_ecma_codegen::text_writer::JsWriter::new(cm.clone(), "\n", &mut buf, None);

    let mut emitter = swc_ecma_codegen::Emitter {
        cfg: Default::default(),
        comments: None,
        cm: cm.clone(),
        wr: writer,
    };

    swc_ecma_codegen::Node::emit_with(&type_decl, &mut emitter).unwrap();

    let code = String::from_utf8(buf).unwrap();
    println!("{}", code);
}
```


### Config

_No response_

### Playground link

_No response_

### Expected behavior

```ts
{
    new<T>(value: T): Obj<T>;
}
```


### Actual behavior

```ts
{
    new(value: T): Obj<T>;
}
```


### Version

```toml
[dependencies]
swc_atoms = "0.4.39"
swc_common = "0.29.37"
swc_ecma_parser = "0.130.2"
swc_ecma_ast = "0.100.1"
swc_ecma_codegen = "0.135.2"
string_cache = "0.8.7"
```

### Additional context

_No response_

Pull request description:
fix(es/codegen): Emit `type_params` for TsConstructSignatureDecl
<!-- 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 #7079 

Patch:
diff --git a/crates/swc_ecma_codegen/src/typescript.rs b/crates/swc_ecma_codegen/src/typescript.rs
index 2c73cb79dd..c60b133f65 100644
--- a/crates/swc_ecma_codegen/src/typescript.rs
+++ b/crates/swc_ecma_codegen/src/typescript.rs
@@ -100,6 +100,10 @@ where
         self.emit_leading_comments_of_span(n.span(), false)?;
 
         keyword!("new");
+        if let Some(type_params) = &n.type_params {
+            space!();
+            emit!(type_params);
+        }
 
         punct!("(");
         self.emit_list(n.span, Some(&n.params), ListFormat::Parameters)?;
@@ -122,8 +126,8 @@ where
         }
 
         keyword!("new");
-        space!();
         if let Some(type_params) = &n.type_params {
+            space!();
             emit!(type_params);
         }
 


Test patch:
diff --git a/crates/swc_ecma_codegen/tests/fixture/issues/7079/input.ts b/crates/swc_ecma_codegen/tests/fixture/issues/7079/input.ts
new file mode 100644
index 0000000000..f7309f09fd
--- /dev/null
+++ b/crates/swc_ecma_codegen/tests/fixture/issues/7079/input.ts
@@ -0,0 +1,3 @@
+interface Foo {
+  new <T>(value: T): Obj<T>;
+}
diff --git a/crates/swc_ecma_codegen/tests/fixture/issues/7079/output.ts b/crates/swc_ecma_codegen/tests/fixture/issues/7079/output.ts
new file mode 100644
index 0000000000..02e85c6cbc
--- /dev/null
+++ b/crates/swc_ecma_codegen/tests/fixture/issues/7079/output.ts
@@ -0,0 +1,3 @@
+interface Foo {
+    new <T>(value: T): Obj<T>;
+}
diff --git a/crates/swc_ecma_transforms_base/tests/ts-resolver/stc/1/output.ts b/crates/swc_ecma_transforms_base/tests/ts-resolver/stc/1/output.ts
index 106c79d40a..20b97579d4 100644
--- a/crates/swc_ecma_transforms_base/tests/ts-resolver/stc/1/output.ts
+++ b/crates/swc_ecma_transforms_base/tests/ts-resolver/stc/1/output.ts
@@ -4,7 +4,7 @@ interface Mixin1__1 {
 class AbstractBase__1 {
     abstractBaseMethod(): void;
 }
-function Mixin2__1<TBase__2 extends abstract new (...args: any[]) => any>(baseClass__2: TBase__2) {
+function Mixin2__1<TBase__2 extends abstract new(...args: any[]) => any>(baseClass__2: TBase__2) {
     class MixinClass__2 extends baseClass__2 implements Mixin1__1 {
         mixinMethod(): void {}
         static staticMixinMethod(): void {}