Clean Code на TypeScript: принципы и примеры для разработчиков

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Clean Code на TypeScript: как писать код, который не стыдно показать

Чистый код (Clean Code) — это не просто модный термин, а фундаментальный подход к разработке, который превращает хаотичный набор инструкций в понятную и поддерживаемую систему. Для TypeScript, как статически типизированного языка, принципы чистого кода приобретают особое значение: строгая типизация и мощные инструменты компилятора позволяют выявлять ошибки на этапе разработки, но только если код структурирован правильно. В этой статье мы разберем ключевые принципы Clean Code применительно к TypeScript, подкрепив их конкретными примерами.

1. Именование переменных, функций и классов

Имя переменной или функции должно отвечать на вопрос "что это?" или "что делает?". В TypeScript, благодаря типизации, имена становятся еще более информативными. Избегайте однобуквенных имен (кроме индексов циклов) и сокращений, которые понятны только вам.

// Плохо
const d = new Date();
const fn = (a: number, b: number) => a + b;

// Хорошо
const currentDate = new Date();
const sum = (firstNumber: number, secondNumber: number): number => firstNumber + secondNumber;

Для классов используйте существительные, для функций — глаголы или глагольные конструкции. Булевы переменные должны начинаться с is, has, should.

// Плохо
const flag = true;
function validate() { /* ... */ }

// Хорошо
const isUserActive = true;
function validateEmail(email: string): boolean { /* ... */ }

2. Принцип единственной ответственности (SRP) для функций

Каждая функция должна делать ровно одну вещь и делать её хорошо. Если функция выполняет несколько действий — разбейте её на более мелкие. TypeScript позволяет строго типизировать входные и выходные данные, что облегчает рефакторинг.

// Плохо: функция ищет пользователя, проверяет пароль и отправляет email
async function loginUser(email: string, password: string): Promise<void> {
    const user = await findUserByEmail(email);
    if (user && user.password === password) {
        await sendLoginEmail(user.email);
        console.log('Login successful');
    }
}

// Хорошо: разделяем ответственность
async function findUserByEmail(email: string): Promise<User | null> { /* ... */ }
function isPasswordValid(inputPassword: string, storedHash: string): boolean { /* ... */ }
async function notifyUserLogin(email: string): Promise<void> { /* ... */ }

async function loginUser(email: string, password: string): Promise<boolean> {
    const user = await findUserByEmail(email);
    if (!user || !isPasswordValid(password, user.passwordHash)) {
        return false;
    }
    await notifyUserLogin(user.email);
    return true;
}

3. Использование типов и интерфейсов вместо any

Одна из главных фишек TypeScript — система типов. Избегайте any любой ценой. Если тип неизвестен заранее, используйте unknown, generics или объединения типов. Это делает код самодокументируемым и защищает от ошибок.

// Плохо
function getData(id: any): any {
    return fetch(`/api/${id}`);
}

// Хорошо
interface ApiResponse<T> {
    data: T;
    error?: string;
}

async function getData<T>(id: string): Promise<ApiResponse<T>> {
    const response = await fetch(`/api/${id}`);
    return response.json();
}

Используйте строгие интерфейсы для описания структуры объектов. Это упрощает рефакторинг и помогает IDE подсказывать свойства.

interface User {
    readonly id: number;
    name: string;
    email: string;
    role: 'admin' | 'user';
}

function updateUserName(user: User, newName: string): User {
    return { ...user, name: newName };
}

4. Обработка ошибок и защитное программирование

Чистый код предусматривает явную обработку исключительных ситуаций. Не игнорируйте возможные ошибки. Используйте Result-типы или специальные классы ошибок.

// Плохо
function divide(a: number, b: number): number {
    return a / b; // Может быть Infinity или NaN
}

// Хорошо
function divide(a: number, b: number): number {
    if (b === 0) {
        throw new Error('Division by zero is not allowed');
    }
    return a / b;
}

// Альтернатива с Result-типом
type Result<T> = { success: true; value: T } | { success: false; error: string };

function safeDivide(a: number, b: number): Result<number> {
    if (b === 0) {
        return { success: false, error: 'Division by zero' };
    }
    return { success: true, value: a / b };
}

5. Комментарии — только когда код не может быть понятнее

Чистый код — это самодокументируемый код. Комментарии должны объяснять "почему", а не "как". Если вы пишете комментарий к простому действию — возможно, стоит переименовать переменную или выделить логику в отдельную функцию.

// Плохо: комментарий объясняет очевидное
// Прибавляем 1 к счетчику
counter += 1;

// Хорошо: комментарий объясняет бизнес-логику
// Скидка применяется только для пользователей с премиум-статусом
if (user.plan === 'premium') {
    applyDiscount(order, 0.1);
}

Заключение

Clean Code на TypeScript — это не набор догм, а инструмент, который делает вашу работу проще и приятнее. Следуя принципам осмысленного именования, единственной ответственности, строгой типизации и грамотной обработки ошибок, вы создаете код, который легко читать, тестировать и поддерживать. Начните с малого: переименуйте одну неочевидную переменную, разбейте большую функцию на две — и вы почувствуете разницу. Помните: код пишется для людей, а компилятор — лишь инструмент проверки.

Блоги

Рекомендаций по книгам