Rust到TypeScript错误处理Skill rust-errors

这个技能用于在Tauri桌面应用中实现Rust和TypeScript之间的错误处理模式,通过discriminated union确保类型安全传递。它涉及定义Rust错误、处理Tauri命令错误,并创建TypeScript可处理的错误类型。关键词包括Rust、TypeScript、错误处理、Tauri、discriminated union、类型安全、跨语言开发、桌面应用。

后端开发 0 次安装 0 次浏览 更新于 3/20/2026

名称: rust-errors 描述: 用于Tauri应用的Rust到TypeScript错误处理模式。用于定义将传递给TypeScript的Rust错误、处理Tauri命令错误或创建discriminated union错误类型。

Rust到TypeScript错误处理

Discriminated Union模式用于错误处理

当通过Tauri命令从Rust传递错误到TypeScript时,使用内部标记的枚举来创建TypeScript可以自然处理的discriminated unions。

Rust错误定义

use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Error, Debug, Serialize, Deserialize)]
#[serde(tag = "name")]
pub enum TranscriptionError {
    #[error("音频读取错误: {message}")]
    AudioReadError { message: String },

    #[error("GPU错误: {message}")]
    GpuError { message: String },

    #[error("模型加载错误: {message}")]
    ModelLoadError { message: String },

    #[error("转录错误: {message}")]
    TranscriptionError { message: String },
}

关键Rust模式

  1. 使用内部标记的枚举: #[serde(tag = "name")] 创建一个区分字段
  2. 遵循命名约定: 枚举变体应为PascalCase
  3. 包含结构化数据: 每个变体可以有字段如 message: String
  4. 单变体枚举可行: 当您想要一致的错误结构时使用
// 用于一致性的单变体枚举
#[derive(Error, Debug, Serialize, Deserialize)]
#[serde(tag = "name")]
enum ArchiveExtractionError {
    #[error("存档提取失败: {message}")]
    ArchiveExtractionError { message: String },
}

TypeScript错误处理

import { type } from 'arktype';

// 定义错误类型以匹配Rust序列化
const TranscriptionErrorType = type({
	name: "'AudioReadError' | 'GpuError' | 'ModelLoadError' | 'TranscriptionError'",
	message: 'string',
});

// 在错误处理中使用
const result = await tryAsync({
	try: () => invoke('transcribe_audio_whisper', params),
	catch: (unknownError) => {
		const result = TranscriptionErrorType(unknownError);
		if (result instanceof type.errors) {
			// 处理意外错误形状
			return WhisperingErr({
				title: '意外错误',
				description: extractErrorMessage(unknownError),
				action: { type: 'more-details', error: unknownError },
			});
		}

		const error = result;
		// 现在我们有了正确类型的discriminated union
		switch (error.name) {
			case 'ModelLoadError':
				return WhisperingErr({
					title: '模型加载错误',
					description: error.message,
					action: {
						type: 'more-details',
						error: new Error(error.message),
					},
				});

			case 'GpuError':
				return WhisperingErr({
					title: 'GPU错误',
					description: error.message,
					action: {
						type: 'link',
						label: '配置设置',
						href: '/settings/transcription',
					},
				});

			// 处理其他情况...
		}
	},
});

序列化格式

Rust枚举序列化为这种TypeScript友好的格式:

// AudioReadError变体
{ "name": "AudioReadError", "message": "解码音频文件失败" }

// GpuError变体
{ "name": "GpuError", "message": "GPU加速失败" }

最佳实践

  1. 一致的错误结构: 所有错误具有相同的形状,带有 namemessage
  2. TypeScript类型安全: 使用arktype进行运行时验证以确保类型安全
  3. 穷尽处理: switch语句提供编译时穷尽性检查
  4. 不要使用 content 属性: 避免 #[serde(tag = "name", content = "data")],因为它创建嵌套结构
  5. 尽可能保持枚举私有: 仅在跨模块使用时公开

要避免的反模式

// 不要: 外部标记(默认行为)
#[derive(Serialize)]
pub enum BadError {
    ModelLoadError { message: String }
}
// 产生: { "ModelLoadError": { "message": "..." } }

// 不要: 带内容的相邻标记
#[derive(Serialize)]
#[serde(tag = "type", content = "data")]
pub enum BadError {
    ModelLoadError { message: String }
}
// 产生: { "type": "ModelLoadError", "data": { "message": "..." } }

// 不要: 当derive有效时手动实现Serialize
impl Serialize for MyError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        // 不必要的复杂性
    }
}

这个模式确保了在Rust-TypeScript边界上干净、类型安全的错误处理,具有最小的样板代码和最大的类型安全。