Почему «работает» — это не про команду?
Представьте: вы открываете чужой PR, а там any на каждом шагу, переменные названы a, b, c, и всё отформатировано так, будто код писал кот, гуляющий по клавиатуре. Знакомо? В одиночку такой код можно и пережить. Но в команде это — путь к конфликтам, багам и бессонным ночам на код-ревью.
Сегодня поговорим о том, как сделать TypeScript в команде не просто инструментом, а надёжным фундаментом. Мы разберём code style и конвенции, которые спасут ваши нервы и ускорят разработку. Без занудства, с живыми примерами.
1. Строгая типизация: ваш первый друг
TypeScript — это про типы. Но многие команды используют его как «TypeScript-lite», оставляя any везде, где лень подумать. Это убивает всю магию. Первая конвенция: запретить any.
Плохо:
function fetchData(url: string): any {
// ...
}
Хорошо:
interface ApiResponse {
id: number;
name: string;
isActive: boolean;
}
function fetchData(url: string): Promise<ApiResponse> {
// ...
}
Когда каждый разработчик явно описывает, что он возвращает и принимает, код становится самодокументируемым. Вы больше не гадаете: «Этот data — строка или объект?». Типы говорят сами за себя.
2. ESLint + Prettier: настройка, которая не обсуждается
Если в вашей команде до сих пор нет единого линтера и форматтера, остановитесь и настройте их прямо сейчас. ESLint ловит логические ошибки и нарушения code style, а Prettier делает код единообразным.
Базовая конфигурация ESLint для TypeScript:
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier" // обязательно в конце
],
"rules": {
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/explicit-function-return-type": "warn",
"no-console": "warn"
}
}
Добавьте Prettier с простыми правилами: табы вместо пробелов (или наоборот, но единообразно), одинарные кавычки, точка с запятой в конце. И включите formatOnSave в IDE. Это спасёт от бесконечных споров про отступы.
3. Именование: говорите на одном языке
Конвенции именования — это как правила дорожного движения. Без них — хаос. В TypeScript приняты такие соглашения:
- camelCase для переменных, функций, методов:
getUserData(),userName - PascalCase для классов, интерфейсов, типов:
UserProfile,ApiResponse - UPPER_SNAKE_CASE для констант, известных на момент компиляции:
MAX_RETRY_COUNT,DEFAULT_TIMEOUT - Префикс I для интерфейсов — спорный, но многие команды его используют:
IUser. Решите это на старте.
Пример плохого нейминга:
const data = { n: 'Alex', a: 30 }; // что такое n и a?
Хорошо:
const userProfile = { name: 'Alex', age: 30 };
4. Структура проекта: не прячьте всё в один файл
Когда проект разрастается, отсутствие структуры — главный враг. Договоритесь о папках заранее. Вот популярный вариант для TypeScript-проекта:
src/— исходный кодsrc/components/— UI-компоненты (если React)src/utils/— утилитарные функцииsrc/types/— глобальные типы и интерфейсыsrc/services/— работа с APIsrc/hooks/— кастомные хуки (если React)
Каждый модуль — отдельная папка с index.ts для экспорта. Это упрощает рефакторинг и тестирование.
5. Комментарии: меньше, но метко
Хороший code style — это когда комментарии не нужны, потому что код говорит сам за себя. Но иногда без них не обойтись. Конвенция: пишите комментарии только там, где код сложен или неочевиден. Не комментируйте очевидное:
// Плохо: бессмысленный комментарий
// Прибавляем 1 к счетчику
counter++;
Лучше так:
// Хорошо: объясняем бизнес-логику
// Пропускаем первого пользователя, так как это тестовый аккаунт
const users = await getUsers();
const filteredUsers = users.slice(1);
Для документации функций используйте JSDoc:
/**
* Получает список активных пользователей.
* @param page - номер страницы для пагинации
* @returns массив пользователей
*/
async function getActiveUsers(page: number): Promise<User[]> {
// ...
}
6. Код-ревью: конвенции в действии
Без code style и конвенций код-ревью превращается в бесконечное «а давай переименуем», «а почему тут any?». Когда у вас есть единый стандарт, ревьюер проверяет логику, а не форматирование. Вот чек-лист для ревью TypeScript-кода:
- Нет ли
anyтам, где можно указать конкретный тип? - Соблюдены ли конвенции именования?
- Есть ли лишние комментарии или их не хватает?
- Не нарушена ли структура проекта?
- Проходит ли код ESLint и Prettier?
Совет: добавьте в CI пайплайн проверку линтера. Если код не проходит — PR не мержится. Жестко, но эффективно.
7. Утилиты и общие типы: DRY для TypeScript
В любой команде есть повторяющиеся паттерны. Выносите их в общие типы и утилиты. Это уменьшает дублирование и ошибки.
// Общий тип для ответа API
export interface ApiResponse<T> {
data: T;
success: boolean;
error?: string;
}
// Утилита для обработки ошибок
export function handleApiError(error: unknown): never {
if (error instanceof Error) {