← 全部文章

把类型当作边界,让错误更早出现

从一个小型状态模型出发,用 TypeScript 表达约束,让调用者更容易写出正确的代码。

此文章暂无英文译文。浏览英文文章 ↗

这是用于展示代码排版与文章目录的示例文章,可按需替换。

当一个函数接受多个可选参数时,调用者往往需要阅读实现,才能知道哪些组合是合法的。把约束放进类型,可以让编辑器在代码运行之前提供反馈。

先描述状态

考虑一个请求结果。它可能尚未完成、已经成功,或者发生错误。比起把所有字段写成可选项,可以用一个联合类型表达不同状态:

type Result<T> =
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; message: string };

这样,“正在加载却带着错误信息”就不再是这个类型允许的状态。

在边界处处理分支

function describeResult(result: Result<string>): string {
  switch (result.status) {
    case 'loading':
      return '正在加载';
    case 'success':
      return result.data;
    case 'error':
      return result.message;
    default: {
      const exhaustive: never = result;
      return exhaustive;
    }
  }
}

当新增一个状态时,穷尽检查可以提醒我们更新依赖这个模型的代码。分支中的字段,也会随状态自动收窄。

类型之外仍然需要验证

TypeScript 的约束存在于编译阶段。从网络、用户输入或文件中读取的数据,仍然需要在运行时校验。一个类型断言不会自动证明外部数据符合预期。

可以把设计拆成两个动作:先在输入边界检查数据,再让内部函数处理已经验证过的模型。

从一个具体约束开始

不必为了类型技巧重构全部代码。先寻找一个经常出错的参数组合或状态,把它明确表达出来,再观察调用处是否变得更简单。

本文结束返回归档 ↗