Skip to content

v11.0.0

Latest
Compare
Choose a tag to compare
@NyxCode NyxCode released this 03 Jun 16:41
· 3 commits to main since this release
a7b73a5

We are excited to announce v11.0.0!

Upgrading from v10.x.x

  • With the serde-compat feature enabled (default), fields annotated with both #[serde(skip_serializing(_if))] and #[serde(default)] are now turned into optional properties.
    See "Improved serde compatibility" under "New features" below
  • The API of the ts_rs::TS trait has slightly changed.
    Some trivial adjustments to your code might be necessary, though only if you interact with ts_rs::TS directly.
    Most users should not be affected by this.

New features

Everything's optional!

With v11, we introduce #[ts(optional_fields)], which can cut down on annoying boilerplace.
This attribute can be applied to structs and has the same effect as adding #[ts(optional)] to every field.

Example:

#[derive(TS)]
#[ts(optional_fields)]
struct Form {
  first_name: Option<String>, // first_name?: string
  last_name: Option<String>, // last_name?: string
  email: Option<String>, // email?: string
}

Improved serde compatibility

In the past, #[serde(skip_serializing)] and #[serde(skip_serializing_if = "..")] were ignored by ts-rs.
With v11, we now take these attributes into account, as long as they are used together with #[serde(default)].
This ensures that the generated type is valid for both serializing and deserializing rust structures by default.

A field annotated with #[serde(skip_serializing_(if))] and #[serde(default)] will be treated as if it was annotated with #[ts(optional = nullable)].
This behavior can be overridden using #[ts(optional = false)].

Example:

// now generates `type User = { nickname?: string | null }`, 
// making it correct for both serialization and deserialization by default.
#[derive(Serialize, Deserialize, TS)]
struct User {
  #[serde(skip_serializing_if = "Option::is_none", default)]
  nickname: Option<String>,
}

More flexible attributes

#[doc = ..], #[ts(rename = "..")] and #[ts(export_to = "..")] now accept arbitrary expressions!
This enables some cool new patterns and makes integrating ts-rs in unusual setups easier.

Example:

// Renamed to the name of the current module
#[derive(TS)]
#[ts(rename = module_path!().rsplit_once("::").unwrap().1)] 
struct Model;

// Comment containing the file path where the type was defined
#[derive(TS)]
#[doc = concat!("Defined in ", file!())]
struct UserGroup { . }

Optional tuple structs

The #[ts(optional)] attribute can now also be applied to fields of tuple structs.

Example:

// generates `type Location = [Country, State, City?]`
#[derive(TS)]
struct Location(Country, State, #[ts(optional)] City);

Full changelog

New Contributors