Введение: Почему ваше ревью кода на TypeScript выглядит как красная лампочка на пульте?
Вы когда-нибудь отправляли pull request, а через час получали 20 комментариев от senior-разработчика, половина из которых начиналась со слов «это можно сделать лучше»? Знакомо. Если вы пишете на TypeScript, но ваш код всё ещё вызывает у коллег желание переписать его с нуля — эта статья для вас.
Мы в PythonLib часто сталкиваемся с ситуациями, когда разработчики, даже зная синтаксис TypeScript, допускают одни и те же ошибки. Эти ошибки не ломают код, но делают его нечитаемым, небезопасным и трудносопровождаемым. Сегодня я покажу вам 10 типичных замечаний, которые senior-ы пишут на code review TypeScript, и как их избежать. Готовьтесь к рефакторингу!
1. «Any» — твой враг, а не друг
Самая частая претензия на любом ревью кода на TypeScript — это использование any. Кажется, что проще написать const data: any = await fetch(...), чем разбираться с типами. Но senior-ы видят это как красную тряпку.
Плохо:
function processUser(user: any) {
console.log(user.name.toUpperCase());
}
Хорошо:
interface User {
id: number;
name: string;
email: string;
}
function processUser(user: User): void {
console.log(user.name.toUpperCase());
}
Почему это важно? TypeScript теряет весь смысл, если вы используете any. Вы буквально отключаете систему типов. Если данные приходят из API — создайте интерфейс. Если тип сложный — используйте unknown с проверками. Это одно из главных правил TypeScript best practices.
2. Игнорирование strict mode
Многие проекты отключают строгий режим в tsconfig.json, потому что «так быстрее» или «типы бесят». Senior-разработчик на TypeScript сразу заметит, что ваш код не проверяет null и undefined.
Плохо (strict: false):
function getLength(str: string) {
return str.length; // str может быть null, и это упадёт
}
Хорошо (strict: true):
function getLength(str: string | null): number {
if (str === null) return 0;
return str.length;
}
Совет: Включайте strict: true в tsconfig.json. Это заставит вас писать более безопасный код. На ревью кода TypeScript это будет плюсом, а не минусом.
3. Магия с типами: избыточная сложность
Иногда разработчики пытаются показать, как они круты, и пишут такие типы, что даже senior-ы чешут голову. Например, условные типы с вложенными дженериками там, где можно обойтись простым интерфейсом.
Плохо (over-engineering):
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
Хорошо (простота):
interface Config {
readonly apiUrl: string;
readonly timeout: number;
}
Senior-ы ценят читаемость кода. Если ваш тип можно заменить на интерфейс с тремя полями — сделайте это. Не усложняйте без необходимости.
4. Неправильная обработка ошибок
Типичная ошибка на code review TypeScript — это try-catch с any или пустой блок catch. Senior-ы сразу укажут на это.
Плохо:
try {
const data = await fetchData();
} catch (e) {
console.log('Ошибка');
}
Хорошо:
try {
const data = await fetchData();
} catch (error: unknown) {
if (error instanceof Error) {
console.error(error.message);
} else {
console.error('Неизвестная ошибка', error);
}
}
Используйте unknown для ошибок. Это заставляет вас проверять тип перед использованием. Senior-ы любят такой подход.
5. Отсутствие типов для функций высшего порядка
Когда вы передаёте колбэки или используете map/filter, часто забывают типизировать параметры. Это приводит к неявному any.
Плохо:
const names = users.map(u => u.name);
Хорошо:
const names: string[] = users.map((user: User) => user.name);
Даже если TypeScript выводит тип, явное указание помогает читать код быстрее. Особенно это важно в больших проектах.
6. Использование enum вместо union types
Enum-ы в TypeScript — это спорная тема. Senior-ы часто рекомендуют использовать union types вместо числовых enum, потому что они проще и безопаснее.
Плохо (enum):
enum Status {
Active,
Inactive,
Pending
}
Хорошо (union):
type Status = 'active' | 'inactive' | 'pending';
Union types легче рефакторить, они не создают лишнего кода при компиляции, и их проще проверять. Это один из советов по TypeScript, который сэкономит вам часы дебага.
7. Неправильная работа с async/await
Многие забывают, что async-функция всегда возвращает Promise. Senior-ы на ревью кода на TypeScript обращают внимание на то, как вы обрабатываете асинхронные вызовы.
Плохо:
async function getData() {
return fetch('/api');
}
// Тип возврата: Promise<Response>
Хорошо:
async function getData(): Promise<Data> {
const response = await fetch('/api');
const data: Data = await response.json();
return data;
}
Всегда указывайте возвращаемый тип для async-функций. Это делает код предсказуемым.
8. Избыточное использование type guards
Защитники типов — это круто, но некоторые разработчики пишут их там, где можно обойтись простым сужением.
Плохо:
function isString(value: unknown): value is string {
return typeof value === 'string';
}
if (isString(input)) { ... }
Хорошо:
if (typeof input === 'string') { ... }
Используйте type guards только тогда, когда логика слож