跳到正文
灵动桌面框架
Esc
本栏目菜单

数据序列化

前后端之间的数据通过 JSON 格式传输。Rust 端使用 serde + serde_json 进行序列化/反序列化。

基本原理

TypeScript 对象 → JSON → Rust 结构体
Rust 结构体 → JSON → TypeScript 对象

Rust 端定义

// src-tauri/src/models/mod.rs
use serde::{Deserialize, Serialize};

/// 应用配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
    pub key: String,
    pub value: String,
}

/// 系统信息
#[derive(Debug, Clone, Serialize)]
pub struct SystemInfo {
    pub os: String,
    pub arch: String,
    pub app_version: String,
    pub data_dir: String,
}

AppConfig 只暴露 key / value 两个字段;数据库表 app_config 里的 created_at / updated_at / deleted_at 是存储细节,不传给前端。

TypeScript 端对应类型

// src/types/config.ts
/** 应用配置 */
export interface AppConfig {
  key: string;
  value: string;
}

// src/types/system.ts
/** 系统信息 */
export interface SystemInfo {
  os: string;
  arch: string;
  appVersion: string;
  dataDir: string;
}

模板里的 SystemInfo 两端命名不一致

Rust 的 SystemInfo 没有加 #[serde(rename_all = "camelCase")],序列化出的字段是 app_version / data_dir;而 TypeScript 类型写的是 appVersion / dataDir。这种情况下前端读 info.appVersion 会得到 undefined。照着写新结构体时,二选一:给 Rust 结构体加 rename_all = "camelCase"(推荐,见下一节),或让 TypeScript 字段也用 snake_case。

命名转换

Rust 使用 snake_case,TypeScript 使用 camelCase。可以用 serde 属性控制:

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UserInfo {
    pub user_name: String,    // → JSON: "userName"
    pub email_addr: String,   // → JSON: "emailAddr"
}

Command 参数名会自动转换

Tauri 2 默认把 Command 参数按 camelCase 暴露给前端:Rust 参数 user_id: String 在前端要写成 invoke('xxx', { userId })。这一转换只作用于顶层参数名,参数里的结构体字段仍按 serde 规则(上面的 rename_all)处理。

Command 中使用

// src-tauri/src/commands/system.rs
use tauri::Manager;

use crate::error::CommandError;
use crate::models::SystemInfo;

/// 获取系统信息
#[tauri::command]
pub fn get_system_info(app: tauri::AppHandle) -> Result<SystemInfo, CommandError> {
    let data_dir = app
        .path()
        .app_data_dir()
        .map(|p| p.to_string_lossy().into_owned())
        .unwrap_or_else(|_| "unknown".into());

    Ok(SystemInfo {
        os: std::env::consts::OS.to_string(),
        arch: std::env::consts::ARCH.to_string(),
        app_version: app.package_info().version.to_string(),
        data_dir,
    })
}

错误类型同样走序列化:CommandError 派生了 Serialize,失败时以 { "code": "...", "message": "..." } 的结构交给前端(见 IPC 通信)。

注意事项

类型对齐

确保 Rust 结构体和 TypeScript 接口的字段名和类型严格对齐,否则会导致运行时反序列化错误或前端读到 undefined。

  • i64 / i32 → number(超过 2^53 的 i64 在 JS 中会丢精度,这类 ID 建议用 String 传)
  • String → string
  • bool → boolean
  • Vec<T> → T[]
  • Option<T> → T | null
  • HashMap<String, T> → Record<string, T>
  • () → void(如 set_config 返回 Result<(), CommandError>,前端对应 invoke<void>)