Rust类型安全与TypeScript集成库specta-typescript的使用,实现Rust到TypeScript的高效类型导出与同步
以下是关于Rust类型安全与TypeScript集成库specta-typescript的使用,实现Rust到TypeScript的高效类型导出与同步的完整示例:
首先安装specta-typescript库:
cargo add specta-typescript
或添加到Cargo.toml:
specta-typescript = "0.0.9"
完整示例代码:
use specta::{specta, Type};
use specta_typescript::export_ts;
// 定义一个Rust结构体
#[derive(Type)]
struct User {
id: String,
name: String,
age: u32,
is_active: bool,
}
// 定义一个Rust枚举
#[derive(Type)]
enum Status {
Active,
Inactive,
Suspended(String),
}
// 定义一个Rust函数
#[specta]
fn get_user(id: String) -> Result<User, String> {
Ok(User {
id,
name: "John Doe".to_string(),
age: 30,
is_active: true,
})
}
fn main() {
// 导出TypeScript类型定义到文件
export_ts("src/types.ts", &[
&User::definition(),
&Status::definition(),
&get_user::__specta__()
]).unwrap();
println!("TypeScript types exported successfully!");
}
生成对应的TypeScript类型文件(src/types.ts):
export type User = {
id: string;
name: string;
age: number;
is_active: boolean;
};
export type Status = "Active" | "Inactive" | { "Suspended": string };
export function get_user(id: string): Promise<Result<User, string>>;
关键点说明:
#[derive(Type)]
宏用于标记需要导出到TypeScript的Rust类型#[specta]
宏用于标记需要导出到TypeScript的Rust函数export_ts
函数将类型定义导出到指定文件- 支持Rust的基本类型、结构体、枚举、Result等复杂类型
这个示例展示了如何:
- 在Rust中定义类型安全的模型
- 使用specta-typescript自动生成TypeScript类型定义
- 保持前端和后端类型系统的同步
- 减少手动维护类型定义的工作量
完整示例demo:
// src/main.rs
use specta::{specta, Type};
use specta_typescript::export_ts;
// 用户数据结构体
#[derive(Type, Debug)]
struct User {
id: String,
username: String,
email: String,
roles: Vec<Role>,
}
// 用户角色枚举
#[derive(Type, Debug)]
enum Role {
Admin,
User,
Guest,
}
// API响应结构体
#[derive(Type, Debug)]
struct ApiResponse<T> {
code: u32,
message: String,
data: Option<T>,
}
// 获取用户信息的API函数
#[specta]
fn fetch_user(id: String) -> ApiResponse<User> {
ApiResponse {
code: 200,
message: "Success".to_string(),
data: Some(User {
id,
username: "rustacean".to_string(),
email: "user@example.com".to_string(),
roles: vec![Role::User],
}),
}
}
fn main() {
// 导出所有类型定义到types.ts文件
export_ts("src/bindings/types.ts", &[
&User::definition(),
&Role::definition(),
&ApiResponse::<User>::definition(),
&fetch_user::__specta__()
]).unwrap();
println!("TypeScript类型定义已成功导出!");
}
生成的TypeScript类型文件(src/bindings/types.ts):
export type User = {
id: string;
username: string;
email: string;
roles: Array<Role>;
};
export type Role = "Admin" | "User" | "Guest";
export type ApiResponse<T> = {
code: number;
message: string;
data: T | null;
};
export function fetch_user(id: string): Promise<ApiResponse<User>>;
这个完整示例展示了:
- 更复杂的嵌套类型导出(结构体包含枚举)
- 泛型结构体的处理(ApiResponse<T>)
- 数组类型的自动转换(Vec<Role> → Array<Role>)
- 完整的Rust到TypeScript类型同步流程
Rust类型安全与TypeScript集成库specta-typescript的使用
介绍
specta-typescript是一个强大的Rust库,用于将Rust类型安全地导出到TypeScript,实现Rust后端与TypeScript前端之间的类型同步。它通过过程宏自动生成TypeScript类型定义,确保两端类型系统的一致性。
主要特点:
- 零运行时开销
- 支持大多数Rust标准库类型
- 可自定义类型导出
- 与serde兼容
- 支持枚举、结构体、元组等复杂类型
安装
在Cargo.toml中添加依赖:
[dependencies]
specta = { version = "1.0", features = ["typescript"] }
serde = { version = "1.0", features = ["derive"] }
基本使用
1. 导出简单结构体
use specta::{Type, export::typescript};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Type)]
struct User {
id: String,
name: String,
age: u32,
is_active: bool,
}
fn main() {
// 导出单个类型
let ts_code = typescript::export::<User>().unwrap();
println!("{}", ts_code);
}
输出TypeScript类型:
export interface User {
id: string
name: string
age: number
is_active: boolean
}
2. 导出多个类型
use specta::{Type, export::typescript};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Type)]
struct Post {
id: String,
title: String,
content: String,
author: User, // 使用前面定义的User类型
}
fn main() {
// 导出多个类型
let ts_code = typescript::export::<(User, Post)>().unwrap();
println!("{}", ts_code);
}
3. 枚举类型导出
#[derive(Serialize, Deserialize, Type)]
enum Status {
Active,
Inactive,
Suspended,
}
#[derive(Serialize, Deserialize, Type)]
enum Message {
Text(String),
Image { url: String, width: u32, height: u32 },
SystemNotification,
}
导出的TypeScript:
export type Status = "Active" | "Inactive" | "Suspended"
export type Message =
| { type: "Text", content: string }
| { type: "Image", url: string, width: number, height: number }
| { type: "SystemNotification" }
高级用法
1. 自定义类型名称
#[derive(Serialize, Deserialize, Type)]
#[specta(rename = "TSUser")]
struct User {
#[specta(rename = "userId")]
id: String,
// ...
}
2. 忽略字段
#[derive(Serialize, Deserialize, Type)]
struct SensitiveData {
public_info: String,
#[specta(skip)]
private_key: String,
}
3. 可选字段
#[derive(Serialize, Deserialize, Type)]
struct Profile {
username: String,
#[specta(optional)]
avatar_url: Option<String>,
}
4. 导出到文件
use specta::{export::typescript, Type};
use std::fs;
fn main() {
let ts_code = typescript::export::<(User, Post, Status)>().unwrap();
fs::write("src/bindings.ts", ts_code).unwrap();
}
与前端集成
在前端项目中,可以直接导入生成的类型定义:
import { User, Post } from './bindings';
async function fetchUser(id: string): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
最佳实践
- 在Rust后端项目中创建一个专门的模块处理类型导出
- 设置构建脚本自动生成类型定义文件
- 将类型定义文件放在前端项目容易访问的位置
- 考虑使用cargo watch自动重新生成类型定义
完整示例Demo
这是一个完整的Rust后端与TypeScript前端集成的示例:
后端Rust代码 (src/main.rs):
use specta::{Type, export::typescript};
use serde::{Serialize, Deserialize};
// 定义API响应结构体
#[derive(Serialize, Deserialize, Type)]
#[specta(rename = "ApiResponse")] // 自定义TypeScript中的类型名称
pub struct ApiResponse<T> {
success: bool,
data: T,
#[specta(optional)] // 标记为可选字段
message: Option<String>,
}
// 定义用户数据结构体
#[derive(Serialize, Deserialize, Type)]
pub struct User {
#[specta(rename = "userId")] // 自定义字段名称
id: String,
username: String,
#[specta(optional)]
email: Option<String>,
role: UserRole,
}
// 定义用户角色枚举
#[derive(Serialize, Deserialize, Type)]
pub enum UserRole {
Admin,
Moderator,
User,
#[specta(rename = "GuestUser")] // 自定义枚举变体名称
Guest,
}
// 导出类型到文件
fn export_types() {
let ts_code = typescript::export::<(ApiResponse<User>, User, UserRole)>()
.expect("Failed to generate typescript types");
std::fs::write("../frontend/src/types/generated.d.ts", ts_code)
.expect("Failed to write typescript types to file");
}
fn main() {
export_types();
println!("TypeScript类型定义已生成并写入文件");
}
生成的前端TypeScript类型定义 (frontend/src/types/generated.d.ts):
export interface ApiResponse<T> {
success: boolean
data: T
message?: string
}
export interface User {
userId: string
username: string
email?: string
role: UserRole
}
export type UserRole = "Admin" | "Moderator" | "User" | "GuestUser"
前端TypeScript使用示例 (frontend/src/api.ts):
import { ApiResponse, User } from './types/generated';
async function fetchUserProfile(userId: string): Promise<ApiResponse<User>> {
const response = await fetch(`/api/users/${userId}`);
return response.json();
}
async function updateUserProfile(user: Partial<User>): Promise<ApiResponse<User>> {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(user),
});
return response.json();
}
这个完整示例展示了:
- 如何在Rust中定义复杂类型(包括结构体、枚举)
- 使用specta的自定义选项(重命名、可选字段等)
- 将类型导出到前端项目
- 在前端TypeScript代码中使用生成的类型
specta-typescript极大地简化了全栈开发中的类型同步工作,减少了手动维护类型定义的工作量和潜在错误,是Rust+TypeScript全栈开发的强大工具。