-
Notifications
You must be signed in to change notification settings - Fork 167
Deriving the TS trait
The TS trait can be easily derived through its #[derive(TS)] macro,
which will automatically handle mapping a Rust type into TypeScript type
definitions.
The #[derive(TS)] macro provides an attribute helper macro called #[ts(...)]
which can help you control how the types will be generated
These are attributes that can be used both with structs and enums
This attribute causes the generation of a test which will create a ts file
containing the TypeScript declaration for your type, as well as any types
it depends on (as long as they implement TS)
Allows you to change where your TypeScript file will be generated.
The default is ./bindings/TypeName.ts, this path is relative to Cargo.toml.
Usage:
#[derive(ts_rs::TS)]
#[ts(export)]
struct MyStruct {
foo: String
}This must be either:
- An absolute path
- A path relative to your crate's
Cargo.toml
The given path will be treated as a directory if it ends with a /
character, in which case a file called TypeName.ts will be created
within the given directory, otherwise the path will be treated as a
file (even without an extension).
Usage:
#[derive(ts_rs::TS)]
#[ts(export, export_to = "../ts_project/bindings/")] // Note that #[ts(export)] is still required
struct MyStruct {
foo: String
}If you see yourself using #[ts_export = "..."] with the same directory
for a lot (or even all) your types, there is a more convenient way to do
this.
Create a directory at the root of your project (the directory that contains
Cargo.toml) called .cargo. Inside the .cargo directory, create a file
called config.toml and type the following:
[env]
TS_RS_EXPORT_DIR = { value = "...", relative = true }Where value is a path to a directory (i.e. it must end with a slash /)
relative to your Cargo.toml file.
Now, using #[ts(export)] without #[ts(export_to = "...")] will result
in exporting to the directory defined in your config.toml file.
Note that if you use #[ts(export_to = "...")] with this config, the path
given to TS_RS_EXPORT_DIR will be concatenated with the path given to
export_to as if they were strings, so using ../foo/bar/ in export_to
will cause problems, due to a currently unresolved issue with parent
components in the middle of paths.
Changes the name of your type's TypeScript representation.
If the feature flag serde-compat is enabled (default), using
#[serde(rename = "...")] will have the same effect.
Usage:
#[derive(ts_rs::TS)]
#[ts(export, rename = "MyType")]
struct MyStruct {
foo: String
}Generates:
export type MyType = { foo: string, };Renames all the fields in your struct or variants in your enum to use a given inflection.
Accepted values are lowercase, snake_case, kebab-case, UPPERCASE,
camelCase, PascalCase and SCREAMING_SNAKE_CASE.
If the feature flag serde-compat is enabled (default), using
#[serde(rename_all = "...")] will have the same effect.
Usage:
#[derive(ts_rs::TS)]
#[ts(export, rename_all = "camelCase")]
struct MyStruct {
foo_bar: String
}Generates:
export type MyStruct = { fooBar: string, };Adds the optional modifier (?) to the TS type, allowing a field to be undefined or missing
#[derive(TS)]
#[ts(export)]
struct Foo {
#[ts(optional)]
bar: u32,
}Generates
export type Foo = { bar?: number, };Adds both the optional modifier and | null to the type
#[derive(TS)]
#[ts(export)]
struct Foo {
#[ts(optional = nullable)]
bar: u32,
}Generates
export type Foo = { bar?: number | null, };Avoids generating TS definitions to a field or variant
#[derive(TS)]
#[ts(export)]
struct Foo {
#[ts(skip)]
bar: u32,
baz: String,
}Generates
export type Foo = { baz: string, };By default, enum type definitions will match serde's externally tagged enums, which means
#[derive(TS)]
#[ts(export)]
enum Message {
Request { id: String, method: String, params: HashMap<String, String> },
Response { id: String, status: u8 },
}Generates:
// Note: this code snipped has been formatted manually to facilitate readability
// The exported code is not guaranteed to match this formatting, even with the
// "format" feature flag
export type Message =
| { "Request": { id: string, method: string, params: Record<string, string>, } }
| { "Response": { id: string, status: number, } };Generates TS types for a serde internally tagged enum (TS calls these "discriminated unions")
#[derive(TS)]
#[ts(tag = "type")]
enum Message {
Request { id: String, method: String, params: HashMap<String, String> },
Response { id: String, status: u8 },
}Geneates
export type Message = { "type": "Request", method: string, params: Record<string, string>, } | { "type": "Response", status: number, };Generates TS types for a serde adjacently tagged enum
#[derive(TS)]
#[ts(tag = "t", content = "c")]
enum Block {
Para(Vec<String>),
Str(String),
}Geneates
export type Block = { "t": "Para", "c": Array<string>, } | { "t": "Str", "c": string, };Generates TS types for a serde untagged enum
#[derive(TS)]
#[ts(untagged)]
enum Message {
Request { id: String, method: String, params: HashMap<String, String> },
Response { id: String, status: u8 },
}Geneates
export type Message = { id: string, method: string, params: Record<string, string>, } | { id: string, status: number, };Equivalent to adding #[ts(rename_all = "..."]
to every variant.
Accepted values are lowercase, snake_case, kebab-case, UPPERCASE,
camelCase, PascalCase and SCREAMING_SNAKE_CASE.