Introduction: why code review in TypeScript is needed
Code review is not just a formal code check before merging. It is a powerful tool for improving project quality, sharing knowledge within the team, and preventing bugs at early stages. When it comes to TypeScript, code review takes on special significance: static typing, a powerful generics system, and strict compiler settings allow catching many errors even before running the application. However, even in TypeScript there are pitfalls that are easy to miss.
In this article, we will break down what to pay attention to when reviewing TypeScript code, and how to give feedback so that it is useful, not offensive.
1. Typing and generics: don't let any ruin everything
One of the main goals of TypeScript is to make types explicit. If any appears in the code, it is almost always a red flag. During code review, check:
- Absence of
any. Replace it withunknownwith subsequent type checking or a specific type. - Correctness of generics. Ensure that type parameters are not lost and do not become too broad. For example:
// Bad: we lose the typefunction getFirst(arr: any[]): any { return arr[0];}
// Good: we preserve the type via a genericfunction getFirst<T>(arr: T[]): T | undefined { return arr[0];}- Typing of API responses. If JSON comes from the server, it should be described by an interface, not
any. - Utility types. Use
Partial,Pick,Omitfor flexible work with objects — this reduces code duplication.
Tip: enable the strict: true and noImplicitAny: true flags in tsconfig.json — this will eliminate most problems at the compilation level.
2. Logic and error handling: don't stay silent about problems
TypeScript does not protect against logical errors, so code review should check business logic and exception handling.
What to look for:
- Handling edge cases. What will happen if the array is empty, the object is
null, or the string is empty? Example:
// Bad: we don't check for the element's existencefunction getUserName(users: User[], id: string): string { return users.find(u => u.id === id)!.name; // may throw an error}
// Good: we checkfunction getUserName(users: User[], id: string): string | null { const user = users.find(u => u.id === id); return user ? user.name : null;}- Asynchronous operations. Ensure that promises are correctly handled with
async/await, and errors are caught intry/catch. - Avoiding mutations. If a function should not change input data, use
readonlyand immutable methods (e.g.,mapinstead offorEachwith modification of an external array).
3. Code style and readability: code is written for people
Even perfectly typed code can be unreadable. Code review is a great time to discuss style.
Key points:
- Naming. Variables, functions, and classes should convey their purpose. Avoid single-letter names (except for loop indices). Example:
fetchUserDatais better thangetData. - Function size. A function should not do more than one thing. If it is longer than 20-30 lines, it is a reason to consider refactoring.
- Comments. Comments should explain why the code is written that way, not what it does. If a comment duplicates the code, delete it.
- Formatting. Use