tsify icon indicating copy to clipboard operation
tsify copied to clipboard

#[serde(flatten)] causes struct to serialize into Map instead of Object

Open Enduriel opened this issue 3 months ago • 2 comments

Given the following rust code:

	#[derive(serde::Serialize, serde::Deserialize, tsify::Tsify)]
	#[serde(rename_all = "camelCase")]
	#[tsify(into_wasm_abi, from_wasm_abi)]
	pub struct Bar {
		content: String,
	}

	#[derive(serde::Serialize, serde::Deserialize, tsify::Tsify)]
	#[serde(rename_all = "camelCase")]
	#[tsify(into_wasm_abi, from_wasm_abi)]
	pub struct Foo {
		#[serde(flatten)]
		bar: Bar,
		more: String,
	}

	#[wasm_bindgen]
	pub fn foobar() -> Foo {
		Foo {
			bar: Bar {
				content: "hello".to_string(),
			},
			more: "world".to_string(),
		}
	}

Calling foobar TS side will give me a map, not a JS Object. So doing

console.log(foobar())

will print

Map(2) { 'content' => 'hello', 'more' => 'world' }

this is rather problematic as it means the value cannot be accessed via the normal object property access syntax.

I am not sure if this is relevant (have not tested without), but I am using serde-wasm-bindgen via the js feature.

Enduriel avatar Sep 23 '25 16:09 Enduriel

Thanks to @pveierland for pointing out to me that I can use hashmap_as_object in

#[derive(serde::Serialize, serde::Deserialize, tsify::Tsify)]
#[serde(rename_all = "camelCase")]
#[tsify(into_wasm_abi, from_wasm_abi, hashmap_as_object)]
pub struct Foo {
	#[serde(flatten)]
	bar: Bar,
	more: String,
}

as a temporary workaround. There's still an underlying bug here but this works as a temporary solution.

Enduriel avatar Sep 26 '25 09:09 Enduriel

These seem to be related.

https://github.com/RReverser/serde-wasm-bindgen/issues/9 https://github.com/serde-rs/serde/issues/1346

madonoharu avatar Oct 05 '25 09:10 madonoharu