Clean Code на TypeScript: принципы и примеры
В современной веб-разработке TypeScript стал стандартом де-факто для создания крупных и надёжных приложений. Однако сам по себе TypeScript не гарантирует качества кода. Чтобы проект оставался гибким, понятным и легко поддерживаемым, необходимо следовать принципам Clean Code. В этой статье мы разберём основные концепции чистого кода на TypeScript с наглядными примерами. Вы узнаете, как писать код, который будет радовать не только компилятор, но и ваших коллег.
Почему Clean Code важен для TypeScript?
TypeScript добавляет в JavaScript статическую типизацию, что уже помогает избежать множества ошибок. Но типы — это лишь инструмент. Без продуманной архитектуры и читаемого стиля код всё равно превращается в «спагетти». Clean Code — это философия, которая делает код:
- Читаемым — любой разработчик быстро поймёт логику.
- Поддерживаемым — изменения в одном месте не ломают всё приложение.
- Масштабируемым — добавление новых функций не требует переписывания половины проекта.
Применение этих принципов в TypeScript позволяет использовать мощь системы типов на полную катушку, создавая самодокументируемый код.
Принцип 1: Именование переменных и функций
Хорошее имя — половина успеха. Имя должно отвечать на вопросы «что?» и «зачем?», а не «как?». Избегайте однобуквенных переменных и сокращений, которые понятны только вам.
Плохой пример:
// Что такое d? А y?
const d = new Date();
const y = d.getFullYear();
const fn = (a: number, b: number) => a + b;
Хороший пример:
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const sum = (firstNumber: number, secondNumber: number): number => {
return firstNumber + secondNumber;
};
Совет: Используйте осмысленные имена. Для булевых значений применяйте префиксы is, has, should. Например: isActive, hasPermission.
Принцип 2: Функции должны быть маленькими и делать одну вещь
Функция не должна отвечать за несколько задач одновременно. Если функция делает больше одного действия — её пора разбивать. Это повышает переиспользуемость и упрощает тестирование.
Плохой пример (функция делает всё сразу):
function processUserData(user: any) {
// Валидация
if (!user.email || !user.name) {
throw new Error('Invalid user');
}
// Форматирование
const formattedUser = {
fullName: user.name.toUpperCase(),
emailDomain: user.email.split('@')[1]
};
// Сохранение в БД
database.save(formattedUser);
// Отправка письма
emailService.sendWelcomeEmail(formattedUser);
}
Хороший пример (разделение ответственности):
function validateUser(user: User): void {
if (!user.email || !user.name) {
throw new Error('Invalid user data');
}
}
function formatUser(user: User): FormattedUser {
return {
fullName: user.name.toUpperCase(),
emailDomain: user.email.split('@')[1]
};
}
async function processUserData(user: User): Promise<void> {
validateUser(user);
const formattedUser = formatUser(user);
await database.save(formattedUser);
await emailService.sendWelcomeEmail(formattedUser);
}
Каждая функция теперь имеет одну чёткую цель, и их легко тестировать по отдельности.
Принцип 3: Используйте типы и интерфейсы для самодокументирования
TypeScript даёт мощные инструменты для описания данных. Не злоупотребляйте типом any — он убивает всю пользу от статической типизации. Определяйте интерфейсы и типы, чтобы код говорил сам за себя.
Плохой пример:
function getDiscount(price: any, user: any) {
if (user.isPremium) {
return price * 0.8;
}
return price;
}
Хороший пример:
interface User {
name: string;
isPremium: boolean;
}
interface Product {
price: number;
title: string;
}
function getDiscountedPrice(product: Product, user: User): number {
const discountRate = user.isPremium ? 0.8 : 1.0;
return product.price * discountRate;
}
Теперь любой разработчик, глядя на сигнатуру функции, понимает, какие данные ожидаются и что будет на выходе. Интерфейсы служат контрактом.
Принцип 4: Избегайте магических чисел и строк
«Магические» значения — это числа или строки, смысл которых неочевиден. Они делают код хрупким и сложным для изменений. Выносите их в константы с понятными именами.
Плохой пример:
if (user.role === 1) {
// Что такое 1? Админ? Модератор?
giveAccessToAdminPanel(user);
}
const timeout = 3000; // Почему 3000? Что это за таймаут?
Хороший пример:
enum UserRole {
Admin = 1,
Moderator = 2,
User = 3
}
const ADMIN_PANEL_ACCESS_TIMEOUT_MS = 3000;
if (user.role === UserRole.Admin) {
giveAccessToAdminPanel(user);
}
setTimeout(() => {
revokeAccess(user);
}, ADMIN_PANEL_ACCESS_TIMEOUT_MS);
Теперь код стал самодокументируемым, а изменение значения константы происходит в одном месте.
Заключение
Clean Code на TypeScript — это не набор жёстких правил, а набор практик, которые делают вашу работу проще и приятнее. Начните с малого: переименуйте нечитаемые переменные, разбейте большую функцию на маленькие, замените any на конкретные типы. Со временем эти привычки войдут в автоматизм, и качество вашего кода вырастет в разы.
Помните: хороший код — это не тот, который работает, а тот, который легко поддерживать. TypeScript даёт для этого отличные инструменты, а Clean Code учит ими правильно пользоваться. Практикуйтесь, рефакторите старые проекты и пишите код, который будет понятен вам через год и вашим коллегам уже сегодня.
<<