12 releases
Uses new Rust 2024
| 0.0.12 | May 7, 2026 |
|---|---|
| 0.0.11 | Mar 30, 2026 |
| 0.0.9 | Jan 12, 2025 |
| 0.0.7 | Aug 4, 2024 |
| 0.0.3 | Jul 24, 2024 |
#1462 in Web programming
104,765 downloads per month
Used in 15 crates
(5 directly)
370KB
8K
SLoC
Specta Serde
This applies Serde macro attributes on your types to the Specta generated types.
Using with Specta TypeScript
specta-serde exposes two format implementations for usage with any of the exporter crates, like specta-typescript:
specta_serde::format: unified shape for both serialize and deserialize.specta_serde::format_phases: split serialize/deserialize shapes.
format (unified shape)
Use format when serde behavior is symmetric and only a single TypeScript type is produced.
Note: This will error with certain Serde attributes like #[serde(rename(serialize = "a", deserialize = "b"))] as it's unclear what is correct.
use specta::Types;
use specta_typescript::Typescript;
#[derive(specta::Type, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct User {
user_id: u32,
}
let types = Types::default().register::<User>();
let output = Typescript::default()
.export(&types, specta_serde::format)
.unwrap();
assert!(output.contains("export type User"));
assert!(output.contains("userId: number"));
You should always prefer format_phases where possible as it will generate a more accurate type.
format_phases (split by direction)
Use format_phases when the wire format can differ between serialization and deserialization. This may produce two different types, TypeName_Serialize and TypeName_Deserialize, to accurately represent both phases. It will produce TypeName as TypeName_Serialize | TypeName_Deserialize so the type can be used in a general format when needed.
This is common with directional serde metadata (serialize_with,
deserialize_with, from, into, try_from) or explicit
#[specta(type = specta_serde::Phased<SerializeTy, DeserializeTy>)] overrides.
use serde::{Deserialize, Serialize};
use serde_with::{OneOrMany, serde_as};
use specta::{Type, Types};
use specta_typescript::Typescript;
#[derive(Type, Serialize, Deserialize)]
#[serde(untagged)]
enum OneOrManyString {
One(String),
Many(Vec<String>),
}
#[serde_as]
#[derive(Type, Serialize, Deserialize)]
struct Filters {
#[serde_as(as = "OneOrMany<_>")]
#[specta(type = specta_serde::Phased<Vec<String>, OneOrManyString>)]
tags: Vec<String>,
}
let types = Types::default().register::<Filters>();
let output = Typescript::default()
.export(&types, specta_serde::format_phases)
.unwrap();
assert!(output.contains("Filters_Serialize"));
assert!(output.contains("Filters_Deserialize"));
assert!(output.contains("OneOrManyString"));
Dependencies
~260–620KB
~13K SLoC