Trait typescript_type_def::TypeDef
source · [−]Expand description
A Rust type that has a corresponding TypeScript type definition.
For a Rust type T
, the TypeDef
trait defines a TypeScript type
which describes JavaScript value that are equivalents of Rust values of
type T
as encoded to JSON using serde_json
. The
types are one-to-one, so decoding from TypeScript to JSON to Rust also
works.
Implementing
Local Types
To derive this trait for your own types, use the
#[derive(TypeDef)]
macro.
Foreign Types
To use types from external crates in your own types, the recommended
approach is to create a newtype wrapper and use the #[type_def(type_of = "T")]
attribute to specify its type:
use serde::{Deserialize, Serialize};
use typescript_type_def::{write_definition_file, TypeDef};
// The Uuid type from the uuid crate does not implement TypeDef
// But we know that it serializes to just a string
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, TypeDef,
)]
#[serde(transparent)]
pub struct Uuid(#[type_def(type_of = "String")] pub uuid::Uuid);
// We can now use our newtype in place of the foreign type
#[derive(Debug, Serialize, Deserialize, TypeDef)]
pub struct User {
pub id: Uuid,
pub name: String,
}
let ts_module = {
let mut buf = Vec::new();
write_definition_file::<_, User>(&mut buf, Default::default()).unwrap();
String::from_utf8(buf).unwrap()
};
assert_eq!(
ts_module,
r#"// AUTO-GENERATED by typescript-type-def
export default types;
export namespace types{
export type Uuid=string;
export type User={"id":types.Uuid;"name":string;};
}
"#
);
The other option if you don’t want to create a newtype is to use
#[type_def(type_of = "T")]
everywhere you use the type:
use serde::{Deserialize, Serialize};
use typescript_type_def::{write_definition_file, TypeDef};
#[derive(Debug, Serialize, Deserialize, TypeDef)]
pub struct User {
#[type_def(type_of = "String")]
pub id: uuid::Uuid,
pub name: String,
}
let ts_module = {
let mut buf = Vec::new();
write_definition_file::<_, User>(&mut buf, Default::default()).unwrap();
String::from_utf8(buf).unwrap()
};
assert_eq!(
ts_module,
r#"// AUTO-GENERATED by typescript-type-def
export default types;
export namespace types{
export type User={"id":string;"name":string;};
}
"#
);
std
Types
TypeDef
is implemented for std
types as follows:
Rust type | TypeScript type |
---|---|
bool | boolean |
String | string |
str | string |
numeric types | number 1 |
() | null |
(A, B, C) | [A, B, C] |
[T; N] | [T, T, ..., T] (an N -tuple) |
Option<T> | T | null |
Vec<T> | T[] |
[T] | T[] |
HashSet<T> | T[] |
BTreeSet<T> | T[] |
HashMap<K, V> | Record<K, V> |
BTreeMap<K, V> | Record<K, V> |
&'static T | T |
Box<T> | T |
Cow<'static, T> | T |
PhantomData<T> | T |
Result<T, E> | { Ok: T } | { Err: E } |
[serde_json
] Types
TypeDef
is implemented for types from the [serde_json
] crate (when the
json_value
crate feature is enabled) as follows:
Rust type | TypeScript type |
---|---|
Value | null | |
Map<K, V> | Record<K, V> |
Number | number |
std
numeric types are emitted as named aliases converted to PascalCase (e.g.Usize
,I32
,F64
,NonZeroI8
, etc.). Since they are simple aliases, they do not enforce anything in TypeScript about the Rust types’ numeric bounds, but serve to document their intended range. ↩