
Tauri Specta 阶段特定类型揭秘完整指南Serde 序列化/反序列化双向类型如何精确推导【免费下载链接】tauri-spectaCompletely typesafe Tauri commands项目地址: https://gitcode.com/gh_mirrors/ta/tauri-spectaTauri Specta是 Tauri 桌面应用的类型安全命令工具它能自动从 Rust 后端生成 TypeScript / JSDoc 绑定让前端调用后端命令时拥有完整的类型提示。而在 Tauri Specta v2 中它默认按照 Serde 的序列化Serialize与反序列化Deserialize两个阶段精确推导出两套类型确保前端拿到的类型与线上传输的 JSON 数据完全一致。什么是「阶段特定类型」一个类型两种形状在 Serde 的世界里同一个 Rust 类型在序列化和反序列化时可能长得不一样典型场景有rename(serialize ..., deserialize ...)字段在两个方向上重命名成不同名字skip_serializing该字段只出现在「前端 → 后端」的请求里后端响应里没有skip_deserializing反过来只有响应里才有如果只生成一个类型来描述它总有一个方向是「不准」的。Tauri Specta 的解法就是阶段特定类型Phase-specific types一个 Rust 类型生成两个 TypeScript 类型别名。export type MyType_Serialize ...; // Rust 序列化出去的形状 export type MyType_Deserialize ...; // 前端要传进去的形状 export type MyType MyType_Serialize; // 默认别名指向序列化形状 官方文档对这个机制的说明见项目文档 src/lib.rs命令参数使用反序列化形状命令返回值使用序列化形状如果两个方向形状完全相同则只输出一个普通类型别名不会画蛇添足。推导原理从 Rust 属性到 TypeScript 别名的三步整个推导过程可以拆成三步核心逻辑都集中在 src/lang/js_ts.rs 中第一步识别 Serde 属性specta::Typederive 宏在展开时会把字段上的 Serde 属性记录到类型元数据里。Tauri Specta 并不自己解析属性而是借助上游的specta-serde库在导出时调用PhasesFormat把类型图「按阶段展开」。第二步按阶段选择数据类型导出器内部的关键函数是 render_reference_dt_for_phase它在渲染每个参数或返回值时先调用select_phase_datatype决定「这一处到底要用哪个阶段的形状」。选择规则非常符合直觉出现位置使用的阶段原因命令的入参Deserialize前端构造的对象要被 Rust 反序列化命令的返回值Serialize这个 JSON 是 Rust 序列化出来的事件的emit载荷Serialize前端发出前需要符合传输形状事件的listen载荷Deserialize收到后要能还原成 Rust 类型第三步生成运行时转换可选如果启用了语义类型如把 Rust 的时间戳转成 JS 的DateTauri Specta 还会在生成代码中内联一段按阶段区分的转换函数见 src/lang/js_ts.rs保证「类型」和「运行时行为」始终同方向一致。真实示例一个字段名的双向重命名官方示例应用里有一个专门演示这个特性的命令定义在 examples/app/src-tauri/src/main.rsRust 结构体的value字段序列化时叫serialized_value反序列化时叫deserialized_value。它自动生成的绑定长这样节选自 examples/app/src/bindings.tsphaseSpecificRename: ( input: PhaseSpecificRename_Deserialize // 入参前端要传 deserialized_value ) __TAURI_INVOKEPhaseSpecificRename_Serialize( // 返回拿到的是 serialized_value phase_specific_rename, { input }, )对应的类型定义在 examples/app/src/bindings.tsexport type PhaseSpecificRename PhaseSpecificRename_Serialize | PhaseSpecificRename_Deserialize; export type PhaseSpecificRename_Deserialize { deserialized_value: string }; export type PhaseSpecificRename_Serialize { serialized_value: string };注意这里MyError的推导也很典型IoError变体的载荷字段被标注#[serde(skip)]所以序列化形状里没有data字段反序列化形状里却是data: null——两套类型各自 100% 精确这是「单一类型」方案做不到的。如何关闭阶段特定类型一行配置如果你确定类型在两个方向上完全一致或者想要更简洁的绑定文件可以在构建器上调用let builder Builder::tauri::Wry::new() .disable_serde_phases(); // 退化为不分阶段的统一模式该配置的定义与说明见 src/builder.rs。开启后导出逻辑会从PhasesFormat切换回普通的specta_serde::Format对照逻辑在 src/lang/js_ts.rs每个类型只输出一份定义。关键源码路径速查清单想了解什么去哪里看阶段特定类型的官方说明src/lib.rs导出器与阶段选择逻辑src/lang/js_ts.rs统一/分阶段格式切换src/lang/js_ts.rsdisable_serde_phases配置项src/builder.rs端到端示例命令定义examples/app/src-tauri/src/main.rs生成的 TypeScript 绑定产物examples/app/src/bindings.ts总结为什么「双向类型」值得你关心✅精确rename、skip_*等 Serde 属性在两个方向上都被如实反映前端不再需要any断言✅零成本默认开启只要类型双向形状一致输出和以前一样简洁✅可控不满意时一行disable_serde_phases()即可退回统一模式Tauri Specta 用「阶段特定类型」把 Serde 的双向语义完整地搬到了前端类型系统里——这正是「Completely typesafe Tauri commands」这个承诺背后最精巧的一块拼图。【免费下载链接】tauri-spectaCompletely typesafe Tauri commands项目地址: https://gitcode.com/gh_mirrors/ta/tauri-specta创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考