给一个 API 响应加上类型断言,并不会改变它在运行时的形状。网络数据、用户输入和本地配置,都可能与我们的预期不同。
类型系统最有价值的用法之一,是提醒我们在哪里还没有建立信任。
让未知保持未知
外部数据进入程序时,使用 unknown 能让不确定性保持可见。只有经过校验,才能进入可信的内部逻辑。
type Author = { name: string; bio: string }
function parseAuthor(value: unknown): Author {
if (
typeof value !== 'object' ||
value === null ||
!('name' in value) ||
!('bio' in value) ||
typeof value.name !== 'string' ||
typeof value.bio !== 'string'
) {
throw new Error('Invalid author data')
}
return { name: value.name, bio: value.bio }
}这个函数做了两件事:验证输入,并创建一个符合内部约定的值。后面的代码不需要重复同一组防御性判断。
让错误靠近来源
如果一篇文章缺少标题,最好在读取文章时就指出文件名和缺失字段,而不是等到页面渲染出一个空白区域。
错误越靠近来源,定位的成本越低。相比笼统的「加载失败」,明确的错误信息也是维护者体验的一部分。
不要把所有可能性带进内部
在边界完成转换之后,内部模型可以更严格。比如把日期统一成 ISO 字符串,把可选标签统一成空数组。
这样,列表组件只需要负责展示。它不必知道数据来自文件、数据库还是 API,也不必在每一行渲染时重新处理缺失值。
从一个边界开始
不需要一次重构整个项目。选择一个经常出错的数据入口,补上校验和清晰的错误信息,再观察下游代码是否因此变简单。
好的类型设计,并不是消灭现实中的不确定性,而是给它一个明确的位置。
感谢你读到这里。
思考没有终点,下一篇见。