ts-rs icon indicating copy to clipboard operation
ts-rs copied to clipboard

bug: `#[serde(flatten)]` is not working propertly on fields of type `HashMap`

Open eythaann opened this issue 7 months ago • 0 comments

Describe the bug HashMaps should be flattenable

To Reproduce

#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, TS)]
pub struct ThirdPartyWidgetSettings {
    /// enable or disable the widget
    pub enabled: bool,
    #[serde(flatten)]
    pub rest: HashMap<String, serde_json::Value>,
}

Expected behavior

// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { JsonValue } from './serde_json/JsonValue.ts';

export type ThirdPartyWidgetSettings = {
  /**
   * enable or disable the widget
   */
  enabled: boolean;
} & ({ [key in string]?: JsonValue });

Screenshots

test handlers::events::export_bindings_seeleneventpayload ... FAILED

failures:

---- handlers::commands::export_bindings_seelencommandreturn stdout ----

thread 'handlers::commands::export_bindings_seelencommandreturn' panicked at C:\Users\dlmqc\.cargo\git\checkouts\ts-rs-4e1afb5ed402ab6a\30ba9d1\ts-rs\src\lib.rs:944:9:
{ [key in string]?: string } cannot be flattened
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- state::settings::export_bindings_settings stdout ----

thread 'state::settings::export_bindings_settings' panicked at C:\Users\dlmqc\.cargo\git\checkouts\ts-rs-4e1afb5ed402ab6a\30ba9d1\ts-rs\src\lib.rs:944:9:   
{ [key in string]?: string } cannot be flattened

---- handlers::commands::export_bindings_seelencommandargument stdout ----

thread 'handlers::commands::export_bindings_seelencommandargument' panicked at C:\Users\dlmqc\.cargo\git\checkouts\ts-rs-4e1afb5ed402ab6a\30ba9d1\ts-rs\src\lib.rs:944:9:
{ [key in string]?: string } cannot be flattened

---- handlers::events::export_bindings_seeleneventpayload stdout ----

thread 'handlers::events::export_bindings_seeleneventpayload' panicked at C:\Users\dlmqc\.cargo\git\checkouts\ts-rs-4e1afb5ed402ab6a\30ba9d1\ts-rs\src\lib.rs:944:9:
{ [key in string]?: string } cannot be flattened


failures:
    handlers::commands::export_bindings_seelencommandargument
    handlers::commands::export_bindings_seelencommandreturn
    handlers::events::export_bindings_seeleneventpayload
    state::settings::export_bindings_settings

Version latest

Additional context As a workaround I'm using a enum as wrapper in meantime this is fixed

use schemars::JsonSchema;

/// This struct is intented to work with ts-rs flattening
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, TS)]
#[serde(untagged)]
pub enum Flatenable<T> {
    Inner(T),
}

impl<T: Default> Default for Flatenable<T> {
    fn default() -> Self {
        Flatenable::Inner(T::default())
    }
}

impl<T> std::ops::Deref for Flatenable<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        match self {
            Flatenable::Inner(inner) => inner,
        }
    }
}

impl<T> std::ops::DerefMut for Flatenable<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        match self {
            Flatenable::Inner(inner) => inner,
        }
    }
}

Now this works fine:

#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, TS)]
pub struct ThirdPartyWidgetSettings {
    /// enable or disable the widget
    pub enabled: bool,
    #[serde(flatten)]
    pub rest: Flatenable<HashMap<String, serde_json::Value>>,
}

eythaann avatar May 17 '25 22:05 eythaann