回到所有文章

TypeScript 的边界:类型之外的真实世界

2 分钟阅读

TypeScript 帮我们发现了很多错误。但有一类问题,它只能提醒我们存在,却无法独自解决:来自应用之外的数据,是否真的符合我们期望的形状?

断言不是验证

这段代码看起来类型完整,但 as User 不会检查服务器的实际返回值。

type User = {
  name: string;
  email: string;
};

const user = await response.json() as User;

如果服务器返回的是错误信息,类型系统不会在运行时帮我们拦下来。

让不确定性停在边界

一种简单的方式,是先把外部数据视为 unknown,再明确验证我们需要的字段。

function isUser(value: unknown): value is User {
  if (typeof value !== 'object' || value === null) {
    return false;
  }

  return (
    'name' in value &&
    typeof value.name === 'string' &&
    'email' in value &&
    typeof value.email === 'string'
  );
}

复杂的数据可以使用 Zod 等校验工具。关键不是选择哪个库,而是保持一个约定:外部数据进入核心逻辑之前,先经过检查。

为失败留出清晰的出口

校验失败不应该只变成控制台里的一行红色文字。页面需要一个能解释发生了什么、并告诉用户下一步可以做什么的状态。

搜索索引加载失败时,显示重试提示;内容为空时,提供返回文章列表的入口。这些状态与“成功状态”同样属于产品。

类型是一份诚实的说明

一个好的类型系统,不应该帮我们掩盖不确定性,而应该让它变得可见。

从 unknown 开始并不意味着麻烦。恰恰相反,它提醒我们:这里是真实世界进入代码的地方,需要多一点认真。

从一个关键词开始探索
↑↓ 选择 ↵ 打开在数字花园里寻找灵感