Repository: Aleph-Alpha/ts-rs
Pull request #336 (2024-06-27 23:05:00)

Allow for flattening of generic parameters
## Goal
Generic parameters currently can't be flattened:
```rust
#[derive(TS)]
#[ts(export)]
struct Item<D> {
    id: String,
    #[ts(flatten)]
    inner: D,
}
```
Serde happily accepts this, and we should too.

The three test cases work, and they are compatible with what serde does with them. There may be edge-cases I currently can't think of, though.  
However, this change definitely wont break any existing code.

## Changes
Tiny change: we just implement `fn inline_flattened()` for the dummy generic types we generate, instead of throwing an error. 

## Checklist

- [x] I have followed the steps listed in the [Contributing guide](https://github.com/Aleph-Alpha/ts-rs/blob/main/CONTRIBUTING.md).
- [x] If necessary, I have added documentation related to the changes made.
- [x] I have added or updated the tests related to the changes made.


NyxCode: damn, that was fast! :D
gustavo-shigueo: > damn, that was fast! :D

I literally logged into GitHub as the PR was being created lmao
NyxCode: I *think* this is what @murl-digital wanted in #335, though it might be unrelated if I misunderstood.
gustavo-shigueo: > I _think_ this is what @murl-digital wanted in #335, though it might be unrelated if I misunderstood.

Looking thorugh the issue, I think this is what they need as well
murl-digital: > I _think_ this is what @murl-digital wanted in #335, though it might be unrelated if I misunderstood.

i clarified what i wanted in the issue just in case, but i think this would fit my usecase (i'll have to check, though)

one potential issue is handling trait bounds, but i think i can just use a concrete type or something.
NyxCode: > one potential issue is handling trait bounds, but i think i can just use a concrete type or something.

Since your definition of `struct Item` doesn't make use of the fact that `D: Document`, I'd consider if you can just remove that bound. Normally, you only need such a bound on a struct definition if you're using an associated type on `Document`.  
Even `std::hashmap::HashMap<K, V>` doesn't constrain `K` or `V`, but only the `impl<K: Hash> HashMap { ... }` block does.
NyxCode: Hm, maybe this should be a patch release instead..

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd15eeb..07ba326 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,11 @@
 ### Features
 ### Fixes
 
+# 9.0.1
+### Fixes
+- Allow using `#[ts(flatten)]` on fields using generic parameters ([#336](https://github.com/Aleph-Alpha/ts-rs/pull/336))
+
+
 # 9.0.0
 
 ### Breaking
diff --git a/Cargo.lock b/Cargo.lock
index 5e6c248..3cb3037 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -70,7 +70,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "swc_macros_common",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
@@ -110,9 +110,9 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "2.5.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
 [[package]]
 name = "bitvec"
@@ -170,9 +170,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
 
 [[package]]
 name = "cc"
-version = "1.0.99"
+version = "1.0.101"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
+checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d"
 
 [[package]]
 name = "cfg-if"
@@ -319,9 +319,9 @@ dependencies = [
 
 [[package]]
 name = "either"
-version = "1.12.0"
+version = "1.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
 
 [[package]]
 name = "equivalent"
@@ -356,7 +356,7 @@ checksum = "fdc9cc75639b041067353b9bce2450d6847e547276c6fbe4487d7407980e07db"
 dependencies = [
  "proc-macro2",
  "swc_macros_common",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
@@ -478,7 +478,7 @@ dependencies = [
  "Inflector",
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
@@ -498,9 +498,9 @@ dependencies = [
 
 [[package]]
 name = "lazy_static"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
@@ -534,9 +534,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
 
 [[package]]
 name = "num-bigint"
-version = "0.4.5"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7"
+checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
 dependencies = [
  "num-integer",
  "num-traits",
@@ -618,7 +618,7 @@ dependencies = [
  "phf_shared",
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
@@ -650,9 +650,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.85"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
 dependencies = [
  "unicode-ident",
 ]
@@ -775,9 +775,9 @@ dependencies = [
 
 [[package]]
 name = "serde_bytes"
-version = "0.11.14"
+version = "0.11.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734"
+checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a"
 dependencies = [
  "serde",
 ]
@@ -790,14 +790,14 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.117"
+version = "1.0.118"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
+checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4"
 dependencies = [
  "indexmap",
  "itoa",
@@ -862,7 +862,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "swc_macros_common",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
@@ -950,7 +950,7 @@ checksum = "695a1d8b461033d32429b5befbf0ad4d7a2c4d6ba9cd5ba4e0645c615839e8e4"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
@@ -961,7 +961,7 @@ checksum = "91745f3561057493d2da768437c427c0e979dff7396507ae02f16c981c4a8466"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
@@ -984,7 +984,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "swc_macros_common",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
@@ -1000,9 +1000,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.66"
+version = "2.0.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
+checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1050,7 +1050,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
@@ -1086,9 +1086,9 @@ dependencies = [
 
 [[package]]
 name = "tinyvec"
-version = "1.6.0"
+version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82"
 dependencies = [
  "tinyvec_macros",
 ]
@@ -1118,7 +1118,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
 
 [[package]]
@@ -1142,7 +1142,7 @@ dependencies = [
 
 [[package]]
 name = "ts-rs"
-version = "9.0.0"
+version = "9.0.1"
 dependencies = [
  "bigdecimal",
  "bson",
@@ -1163,11 +1163,11 @@ dependencies = [
 
 [[package]]
 name = "ts-rs-macros"
-version = "9.0.0"
+version = "9.0.1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
  "termcolor",
 ]
 
@@ -1224,9 +1224,9 @@ dependencies = [
 
 [[package]]
 name = "uuid"
-version = "1.8.0"
+version = "1.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
+checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439"
 dependencies = [
  "getrandom",
  "serde",
@@ -1265,7 +1265,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
  "wasm-bindgen-shared",
 ]
 
@@ -1287,7 +1287,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -1437,5 +1437,5 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.66",
+ "syn 2.0.68",
 ]
diff --git a/macros/Cargo.toml b/macros/Cargo.toml
index 2565661..bbab8dc 100644
--- a/macros/Cargo.toml
+++ b/macros/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ts-rs-macros"
-version = "9.0.0"
+version = "9.0.1"
 authors = ["Moritz Bischof <moritz.bischof1@gmail.com>"]
 edition = "2021"
 description = "derive macro for ts-rs"
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index 845d2af..4be1ce5 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -158,7 +158,7 @@ impl DerivedTS {
                     type WithoutGenerics = #generics;
                     fn name() -> String { stringify!(#generics).to_owned() }
                     fn inline() -> String { panic!("{} cannot be inlined", #name) }
-                    fn inline_flattened() -> String { panic!("{} cannot be flattened", #name) }
+                    fn inline_flattened() -> String { stringify!(#generics).to_owned() }
                     fn decl() -> String { panic!("{} cannot be declared", #name) }
                     fn decl_concrete() -> String { panic!("{} cannot be declared", #name) }
                 }
diff --git a/ts-rs/Cargo.toml b/ts-rs/Cargo.toml
index 5166844..ff6ed58 100644
--- a/ts-rs/Cargo.toml
+++ b/ts-rs/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ts-rs"
-version = "9.0.0"
+version = "9.0.1"
 authors = ["Moritz Bischof <moritz.bischof1@gmail.com>"]
 edition = "2021"
 license = "MIT"
@@ -42,7 +42,7 @@ chrono = { version = "0.4", features = ["serde"] }
 
 [dependencies]
 heapless = { version = ">= 0.7, < 0.9", optional = true }
-ts-rs-macros = { version = "=9.0.0", path = "../macros" }
+ts-rs-macros = { version = "=9.0.1", path = "../macros" }
 dprint-plugin-typescript = { version = "0.90", optional = true }
 chrono = { version = "0.4", optional = true }
 bigdecimal = { version = ">= 0.0.13, < 0.5", features = [


Test patch:
diff --git a/ts-rs/tests/integration/generics_flatten.rs b/ts-rs/tests/integration/generics_flatten.rs
new file mode 100644
index 0000000..85bd61a
--- /dev/null
+++ b/ts-rs/tests/integration/generics_flatten.rs
@@ -0,0 +1,49 @@
+use ts_rs_macros::TS;
+
+// https://github.com/Aleph-Alpha/ts-rs/issues/335
+#[derive(TS)]
+#[ts(export, export_to = "generics/flatten/")]
+struct Item<D> {
+    id: String,
+    #[ts(flatten)]
+    inner: D,
+}
+
+#[derive(TS)]
+#[ts(export, export_to = "generics/flatten/")]
+struct TwoParameters<A, B> {
+    id: String,
+    #[ts(flatten)]
+    a: A,
+    #[ts(flatten)]
+    b: B,
+    ab: (A, B),
+}
+
+#[derive(TS)]
+#[ts(export, export_to = "generics/flatten/")]
+enum Enum<A, B> {
+    A {
+        #[ts(flatten)]
+        a: A,
+    },
+    B {
+        #[ts(flatten)]
+        b: B,
+    },
+    AB(A, B),
+}
+
+#[test]
+fn flattened_generic_parameters() {
+    use ts_rs::TS;
+
+    #[derive(TS)]
+    struct Inner {
+        x: i32,
+    }
+
+    assert_eq!(Item::<()>::decl(), "type Item<D> = { id: string, } & D;");
+    assert_eq!(TwoParameters::<(), ()>::decl(), "type TwoParameters<A, B> = { id: string, ab: [A, B], } & A & B;");
+    assert_eq!(Enum::<(), ()>::decl(), "type Enum<A, B> = { \"A\": A } | { \"B\": B } | { \"AB\": [A, B] };");
+}
diff --git a/ts-rs/tests/integration/main.rs b/ts-rs/tests/integration/main.rs
index cb5ca38..59ba728 100644
--- a/ts-rs/tests/integration/main.rs
+++ b/ts-rs/tests/integration/main.rs
@@ -15,6 +15,7 @@ mod flatten;
 mod generic_fields;
 mod generic_without_import;
 mod generics;
+mod generics_flatten;
 mod hashmap;
 mod hashset;
 mod imports;