Rust的TypeScript类型定义生成工具typescript-type-def的使用,自动生成Rust到TypeScript的类型转换接口
Rust的TypeScript类型定义生成工具typescript-type-def的使用,自动生成Rust到TypeScript的类型转换接口
typescript-type-def是一个用于为Rust类型生成TypeScript类型定义的工具库。它可以帮助你生成一个包含类型定义的TypeScript模块,这些类型定义描述了Rust类型的JSON序列化格式。
主要用途
这个工具主要用于当你需要将Rust类型序列化为JSON(使用serde_json
)并在TypeScript中使用时,可以自动生成对应的TypeScript类型定义,而不需要手动维护两套类型定义。
一个典型的使用场景是开发一个带有Rust后端和TypeScript前端的Web应用程序。如果前后端通信的数据在Rust中定义并使用serde_json
进行编码/解码传输,你可以使用这个工具自动生成这些类型的TypeScript定义文件,以便在前端代码中安全使用。
特性
json_value
:为serde_json
中的JSON值类型添加TypeDef
实现
示例
简单示例
use serde::Serialize;
use typescript_type_def::{
write_definition_file,
DefinitionFileOptions,
TypeDef,
};
#[derive(Serialize, TypeDef)]
struct Foo {
a: usize,
b: String,
}
let ts_module = {
let mut buf = Vec::new();
let options = DefinitionFileOptions::default();
write_definition_file::<_, Foo>(&mut buf, options).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 Usize=number;
export type Foo={"a":types.Usize;"b":string;};
}
"#
);
let foo = Foo {
a: 123,
b: "hello".to_owned(),
};
let json = serde_json::to_string(&foo).unwrap();
// 这个JSON与上面的TypeScript类型定义匹配
assert_eq!(json, r#"{"a":123,"b":"hello"}"#);
大型代码库示例
当处理包含许多类型的大型代码库时,一个有用的模式是声明一个"API"类型别名,列出你想要为其生成定义的所有类型:
use serde::Serialize;
use typescript_type_def::{write_definition_file, TypeDef};
#[derive(Serialize, TypeDef)]
struct Foo {
a: String,
}
#[derive(Serialize, TypeDef)]
struct Bar {
a: String,
}
#[derive(Serialize, TypeDef)]
struct Baz {
a: Qux,
}
#[derive(Serialize, TypeDef)]
struct Qux {
a: String,
}
// 这个类型列出了我们想要为其生成定义的所有顶级类型
// 你不需要在这里列出API中的每种类型,只需要列出那些不会被其他类型引用的类型
// 注意Qux没有被提到,但仍然会被生成,因为它是Baz的依赖
type Api = (Foo, Bar, Baz);
let ts_module = {
let mut buf = Vec::new();
write_definition_file::<_, Api>(&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 Foo={"a":string;};
export type Bar={"a":string;};
export type Qux={"a":string;};
export type Baz={"a":types.Qux;};
}
"#
);
运行时创建类型信息示例
你也可以使用write_definition_file_from_type_infos
和运行时创建的TypeInfo
引用列表来创建定义文件:
use serde::Serialize;
use typescript_type_def::{write_definition_file_from_type_infos, TypeDef};
#[derive(Serialize, TypeDef)]
struct Foo {
a: String,
}
#[derive(Serialize, TypeDef)]
struct Bar {
a: String,
}
#[derive(Serialize, TypeDef)]
struct Baz {
a: Qux,
}
#[derive(Serialize, TypeDef)]
struct Qux {
a: String,
}
// 这个列表包含我们想要为其生成定义的所有顶级类型的类型信息
// 你不需要在这里列出API中的每种类型,只需要列出那些不会被其他类型引用的类型
// 注意Qux没有被提到,但仍然会被生成,因为它是Baz的依赖
let api = vec![
&Foo::INFO,
&Bar::INFO,
&Baz::INFO,
];
let ts_module = {
let mut buf = Vec::new();
write_definition_file_from_type_infos(
&mut buf,
Default::default(),
&api,
)
.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 Foo={"a":string;};
export type Bar={"a":string;};
export type Qux={"a":string;};
export type Baz={"a":types.Qux;};
}
"#
);
完整示例Demo
下面是一个完整的示例,展示如何使用typescript-type-def生成TypeScript类型定义并在实际项目中使用:
// Cargo.toml
// [dependencies]
// serde = { version = "1.0", features = ["derive"] }
// serde_json = "1.0"
// typescript-type-def = "0.5"
use serde::Serialize;
use typescript_type_def::{write_definition_file, TypeDef};
// 定义Rust数据结构
#[derive(Debug, Serialize, TypeDef)]
struct User {
id: u64,
username: String,
email: String,
is_active: bool,
roles: Vec<Role>,
}
#[derive(Debug, Serialize, TypeDef)]
struct Role {
name: String,
permissions: Vec<String>,
}
// 生成TypeScript类型定义
fn generate_ts_definitions() -> String {
let mut buf = Vec::new();
write_definition_file::<_, User>(&mut buf, Default::default()).unwrap();
String::from_utf8(buf).unwrap()
}
fn main() {
// 生成TypeScript类型定义
let ts_def = generate_ts_definitions();
println!("Generated TypeScript definitions:\n{}", ts_def);
// 创建一个User实例并序列化为JSON
let user = User {
id: 123,
username: "john_doe".to_string(),
email: "john@example.com".to_string(),
is_active: true,
roles: vec![
Role {
name: "admin".to_string(),
permissions: vec!["read".to_string(), "write".to_string()],
},
Role {
name: "user".to_string(),
permissions: vec!["read".to_string()],
},
],
};
let json = serde_json::to_string_pretty(&user).unwrap();
println!("\nSerialized JSON:\n{}", json);
}
生成的TypeScript定义如下:
// AUTO-GENERATED by typescript-type-def
export default types;
export namespace types{
export type U64=number;
export type Role={"name":string;"permissions":string[];};
export type User={"id":types.U64;"username":string;"email":string;"is_active":boolean;"roles":types.Role[];};
}
对应的JSON输出:
{
"id": 123,
"username": "john_doe",
"email": "john@example.com",
"is_active": true,
"roles": [
{
"name": "admin",
"permissions": [
"read",
"write"
]
},
{
"name": "user",
"permissions": [
"read"
]
}
]
}
这个示例展示了如何:
- 定义Rust数据结构并使用
TypeDef
派生宏 - 自动生成对应的TypeScript类型定义
- 将Rust数据结构序列化为JSON
- 确保生成的JSON与TypeScript类型定义匹配
你可以将生成的TypeScript定义保存到前端项目的类型定义文件中,然后在TypeScript代码中使用这些类型,确保类型安全。
Rust的TypeScript类型定义生成工具typescript-type-def使用指南
typescript-type-def
是一个用于自动将Rust类型转换为TypeScript类型定义的工具,可以显著简化前后端类型同步的工作流程。
功能特点
- 自动从Rust结构体和枚举生成TypeScript接口和类型
- 支持大多数Rust标准类型到TypeScript的映射
- 可配置的生成选项
- 支持自定义类型转换
安装
将typescript-type-def
添加为你的Cargo.toml中的依赖:
[dependencies]
typescript-type-def = "0.6"
基本用法
1. 为结构体生成TypeScript定义
use typescript_type_def::TypeDef;
#[derive(TypeDef)]
struct User {
id: u32,
username: String,
email: String,
is_active: bool,
preferences: Vec<String>,
}
这会生成对应的TypeScript接口:
interface User {
id: number;
username: string;
email: string;
is_active: boolean;
preferences: string[];
}
2. 为枚举生成TypeScript定义
#[derive(TypeDef)]
enum Status {
Active,
Inactive,
Banned,
}
生成TypeScript联合类型:
type Status = "Active" | "Inactive" | "Banned";
3. 复杂类型示例
#[derive(TypeDef)]
struct ApiResponse<T> {
success: bool,
data: Option<T>,
error: Option<String>,
metadata: HashMap<String, serde_json::Value>,
}
生成TypeScript泛型接口:
interface ApiResponse<T> {
success: boolean;
data?: T;
error?: string;
metadata: { [key: string]: any };
}
高级配置
自定义类型名称
#[derive(TypeDef)]
#[typescript(name = "UserDTO")]
struct User {
// ...
}
忽略字段
#[derive(TypeDef)]
struct User {
id: u32,
#[typescript(skip)]
password_hash: String,
// ...
}
自定义类型转换
#[derive(TypeDef)]
struct Custom {
#[typescript(type = "string")]
uuid: Uuid,
}
生成TypeScript文件
你可以创建一个构建脚本(build.rs
)来自动生成TypeScript定义文件:
use std::fs::File;
use std::io::Write;
use typescript_type_def::{export_types, DefinitionFile};
fn main() {
let mut file = DefinitionFile::new();
export_types![
User,
Status,
ApiResponse
]
.to_file(&mut file)
.unwrap();
let ts = file.to_string();
File::create("types.d.ts")
.and_then(|mut f| f.write_all(ts.as_bytes()))
.unwrap();
}
完整示例demo
下面是一个完整的示例,展示如何使用typescript-type-def生成TypeScript类型定义:
- 首先在Cargo.toml中添加依赖:
[dependencies]
typescript-type-def = "0.6"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "0.8", features = ["serde", "v4"] }
- 创建Rust结构体和枚举:
use serde::Serialize;
use typescript_type_def::TypeDef;
use std::collections::HashMap;
use uuid::Uuid;
// 用户结构体
#[derive(TypeDef, Serialize)]
struct User {
id: u32,
username: String,
email: String,
#[typescript(skip)] // 跳过密码字段
password_hash: String,
#[typescript(type = "string")] // 自定义UUID类型为字符串
user_uuid: Uuid,
roles: Vec<Role>,
}
// 用户角色枚举
#[derive(TypeDef, Serialize)]
enum Role {
Admin,
Moderator,
User,
}
// API响应泛型结构体
#[derive(TypeDef, Serialize)]
struct ApiResponse<T> {
success: bool,
data: Option<T>,
error: Option<String>,
metadata: HashMap<String, serde_json::Value>,
}
- 创建build.rs生成TypeScript定义文件:
use std::fs::File;
use std::io::Write;
use typescript_type_def::{export_types, DefinitionFile};
fn main() {
let mut file = DefinitionFile::new();
// 导出所有需要生成TypeScript定义的类型
export_types![
User,
Role,
ApiResponse
]
.to_file(&mut file)
.unwrap();
// 将生成的TypeScript定义写入文件
let ts = file.to_string();
File::create("src/types.d.ts")
.and_then(|mut f| f.write_all(ts.as_bytes()))
.unwrap();
}
- 生成的types.d.ts文件内容:
interface User {
id: number;
username: string;
email: string;
user_uuid: string;
roles: Role[];
}
type Role = "Admin" | "Moderator" | "User";
interface ApiResponse<T> {
success: boolean;
data?: T;
error?: string;
metadata: { [key: string]: any };
}
注意事项
- 确保你的Rust类型实现了
serde::Serialize
,因为typescript-type-def
依赖serde的类型系统 - 复杂生命周期或泛型可能会有特殊处理需求
- 某些Rust特有类型(如
Duration
)需要自定义转换
这个工具可以大幅减少在Rust后端和TypeScript前端之间保持类型同步的工作量,特别适合全栈Rust开发者使用。