停止抛出异常。改用 Option 和 Result。

发布: (2026年2月20日 GMT+8 20:10)
4 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的文章正文(除代码块、URL 之外的文字),我将按照要求把它翻译成简体中文并保持原有的 Markdown 格式。

JavaScript 错误处理的问题

function getUser(id: number): User | null {
  // ...
}

调用者必须记得进行 null 检查。类型系统会提示他们,但没有任何东西能阻止这种情况:

const user = getUser(42);
console.log(user.name); // 如果 user 为 null,运行时会抛出 TypeError

更糟糕的模式是将可能的失败隐藏在 async 函数中:

async function fetchConfig(): Promise {
  // can throw network error, parse error, validation error...
  // none of these appear in the type signature
}

这些错误是不可见的,导致调用者不知道需要处理什么。

介绍 TypeScript 中的 OptionResult

Rust 的 OptionResult 在类型签名中显式地表示可能的缺失或失败。@rslike/std 将同样的思想引入了 TypeScript。

npm i @rslike/std

使用 Option

import { Some, None, Option, match } from "@rslike/std";

function findUser(id: number): Option {
  const user = db.find(u => u.id === id);
  return user ? Some(user) : None();
}

安全提取

const opt = findUser(42);

// Fallback value
const user = opt.unwrapOr(guestUser);

模式匹配

const greeting = match(
  opt,
  (user) => `Hello, ${user.name}!`,
  () => "Hello, guest!"
);

转换

const displayName = findUser(42)
  .map(u => `${u.firstName} ${u.lastName}`)
  .unwrapOr("Unknown User");

链式调用 Options

const avatar = findUser(42)
  .flatMap(u => findAvatar(u.avatarId))
  .unwrapOr(defaultAvatar);

基础 API

const opt = Some("hello");
opt.isSome();      // true
opt.isNone();      // false
opt.unwrap();      // "hello"

const empty = None();
empty.isNone();                // true
empty.unwrapOr("fallback");    // "fallback"
empty.unwrap();                // throws UndefinedBehaviorError — intentional!

使用 Result

import { Ok, Err, Result, match } from "@rslike/std";

function divide(a: number, b: number): Result {
  return new Result((ok, err) => {
    if (b === 0) {
      err("Division by zero");
    } else {
      ok(a / b);
    }
  });
}

检查 Result

const r = divide(10, 2);
r.isOk();        // true
r.unwrap();      // 5

const bad = divide(10, 0);
bad.isErr();          // true
bad.unwrapErr();      // "Division by zero"
bad.unwrapOr(0);      // 0

使用 Result 解析 JSON

function parseJSON(raw: string): Result {
  return new Result((ok, err) => {
    try {
      ok(JSON.parse(raw));
    } catch (e) {
      err(e as SyntaxError);
    }
  });
}

const config = parseJSON(rawInput)
  .map(data => validate(data))
  .mapErr(e => `Invalid config: ${e.message}`)
  .unwrapOr(defaults);

Result 进行匹配

const message = match(
  parseJSON(rawInput),
  (data) => `Loaded: ${JSON.stringify(data)}`,
  (err) => `Error: ${err.message}`
);

match 实用工具

match 支持布尔值、OptionResult,提供穷尽的双分支分派。

import { match } from "@rslike/std";

// Boolean
match(isAdmin, (t) => "admin panel", (f) => "dashboard");

// Option
match(someOption, (value) => `Got: ${value}`, () => "nothing");

// Result
match(someResult, (n) => n * 2, (e) => -1);

TypeScript 会根据输入推断回调参数的类型,防止将错误处理器误用为成功处理器。

全局导入(可选)

// entry.ts — once
import "@rslike/std/globals";

// Anywhere else in your app — no imports needed
const x = Some(42);
const r = Ok("success");
const n = None();
const e = Err(new Error("oops"));

代码审查的好处

OptionResult 出现在函数签名中时,讨论从 “我们忘记处理 null/异常了吗?” 转变为 “预期的契约是什么?”

BeforeAfter
function getSession(token: string): Session | nullfunction getSession(token: string): Option
async function createOrder(cart: Cart): Promiseasync function createOrder(cart: Cart): Promise>

安装

npm i @rslike/std
0 浏览
Back to Blog

相关文章

阅读更多 »

Rust 调试调查 2026

概述:我们正在发起一项 Rust 调试调查。调试 Rust 代码常被认为是 Rust 开发者面临的最大挑战之一。虽然它是 pos...