引言:为什么需要对 TypeScript 代码进行评审
代码评审不仅仅是合并前的一道形式化检查。它是提升项目质量、促进团队知识共享以及在早期阶段预防缺陷的强大工具。对于 TypeScript 而言,代码评审具有特殊意义:静态类型、强大的泛型系统以及严格的编译器设置,使得许多错误甚至在运行应用程序前就能被捕获。然而,即使在 TypeScript 中,也有一些容易忽略的陷阱。
在本文中,我们将详细阐述评审 TypeScript 代码时需要注意哪些方面,以及如何提供既有用又不伤人的反馈。
1. 类型与泛型:别让 any 毁了一切
TypeScript 的主要目标之一是让类型明确。如果代码中出现了 any,这几乎总是一个危险信号。在代码评审时,请检查:
- 避免使用
any。 将其替换为unknown并随后进行类型检查,或者替换为具体的类型。 - 泛型的正确性。 确保类型参数既不会丢失,也不会变得过于宽泛。例如:
// 不好:丢失了类型function getFirst(arr: any[]): any { return arr[0];}
// 好:通过泛型保留了类型function getFirst<T>(arr: T[]): T | undefined { return arr[0];}- API 响应的类型。 如果 JSON 数据来自服务器,应该用接口来描述,而不是
any。 - 工具类型。 使用
Partial、Pick、Omit来灵活处理对象——这可以减少代码重复。
提示:在 tsconfig.json 中启用 strict: true 和 noImplicitAny: true 标志——这将在编译层面消除大部分问题。
2. 逻辑与错误处理:别对问题保持沉默
TypeScript 并不能防止逻辑错误,因此代码评审应检查业务逻辑和异常处理。
需要关注的点:
- 处理边界情况。 如果数组为空、对象为
null或字符串为空,会发生什么?示例:
// 不好:我们未检查元素是否存在function getUserName(users: User[], id: string): string { return users.find(u => u.id === id)!.name; // 可能抛出错误}
// 好:我们进行了检查function getUserName(users: User[], id: string): string | null { const user = users.find(u => u.id === id); return user ? user.name : null;}- 异步操作。 确保 Promise 通过
async/await被正确处理,并且错误在try/catch中被捕获。 - 避免变更。 如果某个函数不应更改输入数据,请使用
readonly和不可变方法(例如,使用map而不是修改外部数组的forEach)。
3. 代码风格与可读性:代码是为人类编写的
即使类型完美的代码也可能难以阅读。代码评审是讨论风格的好时机。
关键点:
- 命名。 变量、函数和类应传达其用途。避免使用单个字母的命名(循环索引除外)。例如:
fetchUserData比getData更好。 - 函数大小。 一个函数不应做多于一件事。如果其长度超过 20-30 行,就有理由考虑重构。
- 注释。 注释应解释代码为什么这样写,而不是做了什么。如果注释只是重复代码,请删除它。
- 格式化。 使用