Trait typescript_type_def::TypeDef
source · pub trait TypeDef: 'static {
const INFO: TypeInfo;
}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, str | string |
PathBuf, Path | string |
CString, CStr, OsString, OsStr | string |
IpAddr | string |
| numeric types | number1 |
() | null |
(A, B, C) | [A, B, C] |
[T; N] | [T, T, ..., T] (an N-tuple) |
Option<T> | T | null |
Vec<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 |
stdnumeric 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. ↩