Code review в TypeScript: что проверять и как давать обратную связь на практике
Code review — это не просто формальность, а мощный инструмент повышения качества кода. В TypeScript, с его богатой системой типов, ревью может быть особенно эффективным. В этой статье мы разберём, на что обращать внимание при проверке TypeScript-кода, и как давать обратную связь, чтобы она была полезной, а не обидной. Все примеры — на реальном коде.
1. Типы и аннотации: избегаем `any` и используем строгость
Первое, что бросается в глаза на ревью TypeScript-кода — это типы. TypeScript создан для того, чтобы ловить ошибки на этапе компиляции, поэтому any — это красный флаг.
Что проверять:
- Наличие
any. Каждоеanyдолжно быть оправдано. Если это миграция с JS — ок, но в новом коде — нет. - Корректность типов. Не используйте
stringтам, где нуженenumилиunion type. - Излишняя типизация. TypeScript умеет выводить типы. Не пишите
const x: number = 5— пишитеconst x = 5. - Строгие настройки. Проверьте, что в
tsconfig.jsonвключеныstrict: true,noImplicitAny,strictNullChecks.
Пример плохого кода:
function processData(data: any) {
return data.name.toLowerCase();
}
Как исправить:
interface User {
name: string;
}
function processData(data: User): string {
return data.name.toLowerCase();
}
Как дать обратную связь:
Вместо «Ты используешь any, это плохо» скажите: «Здесь any отключает проверку типов. Давай опишем интерфейс User — это повысит безопасность и читаемость кода».
2. Работа с null и undefined: strictNullChecks спасает жизнь
Ошибки Cannot read property of undefined — классика. TypeScript с strictNullChecks помогает их избежать, но только если разработчик правильно обрабатывает nullable-значения.
Что проверять:
- Проверка на null/undefined перед обращением к свойствам.
- Использование optional chaining (
?.) — это современно и безопасно. - Оператор
!(non-null assertion) — используйте только если на 100% уверены, что значение не null. Лучше заменить на явную проверку. - Правильное использование
??(nullish coalescing) вместо||для значений по умолчанию.
Пример плохого кода:
function getCity(user: User | null): string {
return user!.address!.city; // Опасно!
}
Как исправить:
function getCity(user: User | null): string {
return user?.address?.city ?? 'Unknown';
}
Как дать обратную связь:
«Использование ! здесь рискованно — если user окажется null, упадёт ошибка. Давай заменим на ?. и ?? — это безопасно и читаемо».
3. Дженерики и утилитарные типы: не усложняйте без нужды
Дженерики — мощная фича, но их легко переусложнить. Ревьюер должен следить за балансом между гибкостью и читаемостью.
Что проверять:
- Избыточная сложность. Если дженерик используется всего один раз, возможно, он не нужен.
- Правильное использование
extends— ограничивайте дженерики, чтобы они не принимали всё подряд. - Утилитарные типы (
Partial,Pick,Omit,Record) — их использование упрощает код. - Типы возвращаемых значений — функция с дженериком должна возвращать что-то осмысленное, а не
any.
Пример плохого кода:
function getProperty<T, K>(obj: T, key: K) {
return (obj as any)[key];
}
Как исправить:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
Как дать обратную связь:
«Здесь дженерик K не ограничен — можно передать любое значение, и TypeScript не проверит ключ. Добавь extends keyof T — это даст автодополнение и безопасность».
4. Async/await и обработка ошибок: не забывайте про reject
Асинхронный код в TypeScript — частая причина трудноуловимых багов. Особенно если разработчик не обрабатывает ошибки или забывает про типы промисов.
Что проверять:
- Возвращаемый тип промиса — функция должна возвращать
Promise<T>, а неPromise<any>. - Обработка ошибок — есть ли
try/catch? Если нет, то как ошибка будет обработана выше? - Параллельные запросы — используйте
Promise.allилиPromise.allSettled, а не последовательныеawait. - Неиспользуемые промисы — если вы не ждёте результат, убедитесь, что это намеренно.
Пример плохого кода:
async function fetchUsers() {
const response = await fetch('/api/users');
return response.json(); // Тип - any
}
Как исправить:
interface User {