Pressidian
花园入口
笔记
项目
关于
实验室
GitHub
花园入口
笔记
项目
关于
实验室
GitHub

KNOWLEDGE PATHS

笔记库
当前位置
笔记库/前端/项目笔记/代达罗斯/模式

用neverthrow进行错误处理

1 分钟阅读 · Note

目录树 578 篇

            • 表单最佳实践指南
            • 双层级导航结构
            • 以schema为中心的
            • 异步三态切换
            • 用neverthrow进行错误处理
            • Anatomy
            • cn
            • LoadingState&useList的组合
            • procedure中的service位置
            • scrollbar-gutter
            • TailwindCSS
            • TanStack Router 路由模式
            • useDebounce
            • useForm
            • void
          • 项目待做
          • 性能优化
          • UI设计
      • 前端技术栈
    • 笔记目录
    • CLAUDE.md
    • Vue 组件与 Render 函数

关联笔记 6

↗Archetype的服务层反向链接↗tRPC简述反向链接↗表单最佳实践指南同一路径↗双层级导航结构同一路径↗以schema为中心的同一路径↗异步三态切换同一路径
  • 用neverthrow进行错误处理

用neverthrow进行错误处理

这个模式来自 Rust 的 Result 枚举。核心思路是:用返回值代替 throw。

传统的 try-catch 是这样的:

  // 传统写法 — 错误被"扔"出去                                                              
  try {                                                       
    const data = await someService();  // 你不知道它会扔什么
    return { data };
  } catch (error) {
    // error 是 unknown 类型,也不知道到底是谁扔的
  }

neverthrow 的做法是让函数 主动返回 Ok 或 Err,不扔异常:

  // neverthrow 写法 — 错误是函数的正常返回值
  async function createRule(input) {
    if (!input.name) {
      return err(new Error('名称不能为空'));  // 返回 Err,不 throw
    }
    return ok(await db.insert(rule).values(input));  // 返回 Ok
  }

.match() 是这个类型的"分叉处理"方法。它强制你必须同时处理成功和失败两种情况:

  const result = await createRule(input);

  return result.match(
    // 第一个回调:成功分支,data 就是 ok() 里的值
    (data) => ({ data }),
    // 第二个回调:失败分支,error 就是 err() 里的 Error
    (error) => { throw new TRPCError({ code: 'BAD_REQUEST', message: error.message }) }
  );

为什么这样做? 拆开看:

  1. 函数不可能"意外崩溃" — Result 把错误变成了类型系统的一部分,用 err() 返回的错误照样会被 .match()接收到
  2. .match() 强制两个分支都写 — 你无法忘记处理错误,TypeScript 会让你编译不过
  3. 错误信息不丢失 — 一路传到 router 再转成 tRPC 的 TRPCError,最终变成前端能理解的 HTTP 错误响应

数据流向:DAO err() → Service 透传 → Router .match() → TRPCError → 前端