PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • Подписка
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюсPurpleMax
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • Подписка
    • AI для кодаНовое
    • Сообщество
    Главная
    Сообщество
    Паттерны проектирования на TypeScript: SOLID с примерами

    Паттерны проектирования на TypeScript: SOLID с примерами

    Аватар автора Паттерны проектирования на TypeScript: SOLID с примерами

    Антон Ларичев

    Иконка календаря13 июня 2026
    typescriptsolidпаттерны проектированияоопархитектураmiddleИконка уровня middle
    Картинка поста Паттерны проектирования на TypeScript: SOLID с примерами

    Введение

    Принципы SOLID — это пять фундаментальных правил объектно-ориентированного проектирования, сформулированных Робертом Мартином. Они помогают писать гибкий, расширяемый и поддерживаемый код. TypeScript благодаря строгой типизации, интерфейсам и модификаторам доступа отлично подходит для демонстрации этих принципов на практике. В этой статье разберём каждый принцип SOLID с примерами кода и покажем, как они работают в реальных проектах.

    S — Single Responsibility Principle

    Принцип единственной ответственности гласит: класс должен иметь только одну причину для изменения. Часто это интерпретируют как «один класс — одна задача».

    Плохой пример: класс, который и хранит данные пользователя, и работает с базой, и отправляет письма.

    // Нарушение SRP: класс делает слишком много
    class User {
      constructor(public email: string, public name: string) {}
    
      saveToDatabase(): void {
        // логика сохранения в БД
      }
    
      sendWelcomeEmail(): void {
        // логика отправки письма
      }
    }
    

    Правильный вариант — разделить ответственности:

    class User {
      constructor(public email: string, public name: string) {}
    }
    
    class UserRepository {
      save(user: User): void {
        // сохранение в базу данных
      }
    }
    
    class EmailService {
      sendWelcome(user: User): void {
        // отправка приветственного письма
      }
    }
    

    Теперь изменение схемы БД не затронет логику отправки писем, и наоборот.

    O — Open/Closed Principle

    Классы должны быть открыты для расширения, но закрыты для модификации. Добавление нового поведения не должно требовать правок старого кода.

    interface PaymentMethod {
      pay(amount: number): void;
    }
    
    class CardPayment implements PaymentMethod {
      pay(amount: number): void {
        // оплата картой
      }
    }
    
    class CryptoPayment implements PaymentMethod {
      pay(amount: number): void {
        // оплата криптовалютой
      }
    }
    
    class Checkout {
      process(method: PaymentMethod, amount: number): void {
        method.pay(amount);
      }
    }
    

    Добавление нового способа оплаты сводится к созданию нового класса, реализующего PaymentMethod. Класс Checkout менять не нужно.

    L — Liskov Substitution Principle

    Объекты подкласса должны быть взаимозаменяемы с объектами базового класса без нарушения корректности программы.

    Классический пример — Прямоугольник и Квадрат. Если Square наследуется от Rectangle и переопределяет сеттеры так, что ширина и высота всегда равны, это сломает код, который ожидает поведение прямоугольника.

    // Правильный подход: общий интерфейс вместо наследования
    interface Shape {
      area(): number;
    }
    
    class Rectangle implements Shape {
      constructor(private width: number, private height: number) {}
      area(): number {
        return this.width * this.height;
      }
    }
    
    class Square implements Shape {
      constructor(private side: number) {}
      area(): number {
        return this.side * this.side;
      }
    }
    

    Здесь обе фигуры реализуют контракт Shape без нарушения ожидаемого поведения.

    I — Interface Segregation Principle

    Клиенты не должны зависеть от методов, которые они не используют. Лучше несколько узких интерфейсов, чем один «жирный».

    // Плохо: один большой интерфейс
    interface Worker {
      work(): void;
      eat(): void;
      sleep(): void;
    }
    
    // Хорошо: разделение по ролям
    interface Workable {
      work(): void;
    }
    
    interface Eatable {
      eat(): void;
    }
    
    class Robot implements Workable {
      work(): void {
        // робот работает, но не ест
      }
    }
    
    class Human implements Workable, Eatable {
      work(): void {}
      eat(): void {}
    }
    

    Теперь класс Robot не обязан реализовывать ненужные методы.

    D — Dependency Inversion Principle

    Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.

    interface Logger {
      log(message: string): void;
    }
    
    class ConsoleLogger implements Logger {
      log(message: string): void {
        console.log(message);
      }
    }
    
    class OrderService {
      // зависимость от абстракции, а не от конкретной реализации
      constructor(private logger: Logger) {}
    
      createOrder(): void {
        this.logger.log('Заказ создан');
      }
    }
    
    const service = new OrderService(new ConsoleLogger());
    service.createOrder();
    

    Легко заменить ConsoleLogger на FileLogger или мок в тестах — OrderService об этом не узнает.

    Частые ошибки

    Начинающие разработчики часто впадают в крайности. Перечислим типичные проблемы.

    • Чрезмерное дробление классов ради SRP. Если класс делает одно осмысленное действие — этого достаточно, не нужно выделять каждую строку в отдельный модуль.
    • Использование наследования вместо композиции. LSP легко нарушить, когда подкласс пытается «уточнить» поведение родителя. Композиция и интерфейсы безопаснее.
    • Преждевременные абстракции. Создание интерфейсов для классов, у которых заведомо одна реализация, усложняет код без выгоды. Вводите абстракции, когда появляется второй сценарий использования.
    • Игнорирование DIP при работе с фреймворками. Прямое создание зависимостей через new внутри классов затрудняет тестирование. Используйте внедрение через конструктор или DI-контейнеры.
    • Смешение SRP и слоистой архитектуры. SRP относится к причинам изменения, а не к количеству методов в классе.

    Заключение

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

    Иконка глаза820

    Комментарии

    0

    Постройте личный план изучения TypeScript с нуля - полный курс и паттерны проектирования до уровня Middle — бесплатно!

    TypeScript с нуля - полный курс и паттерны проектирования — часть карты развития Frontend, Backend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    React и Redux Toolkit

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Zustand

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Neovim

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста Neovim + avante.nvim с Claude из России: настройка
    Иконка аватараАнтон
    Иконка календаря27 октября 2026
    AI-инструментыAnthropicразработкаmiddleИконка уровня middle

    Neovim + avante.nvim с Claude из России: настройка

    avante.nvim — плагин для Neovim, который добавляет ИИ-ассистента в стиле Cursor: боковую панель с чатом по коду, правки выделенного фрагмента и применение изменений прямо в буфер. С Claude он работает через провайдер `claude`, но из России напрямую не подключится: API Anthropic отклоняет российские адреса, а ключ оплачивается зарубежной картой. Решение — указать в конфиге плагина свой адрес API (`endpoint`) и ключ AI для кода от PurpleSchool с оплатой в рублях. Ниже — установка через lazy.nvim, актуальный конфиг, горячие клавиши и частые ошибки.

    Иконка чипа0
    Иконка глаза29
    Иконка комментариев0
    Картинка поста OpenCode: пользовательские провайдеры недоступны — что делать
    Иконка аватараАнтон
    Иконка календаря26 октября 2026
    AI-инструментыapiразработкаjuniorИконка уровня junior

    OpenCode: пользовательские провайдеры недоступны — что делать

    Ошибка «Пользовательские провайдеры недоступны на этом сервере» (в английском интерфейсе — «Custom providers are unavailable on this server») появляется в OpenCode Desktop и веб-интерфейсе OpenCode, когда вы сохраняете своего провайдера через «Настройки → Провайдеры → Пользовательский провайдер». Это ошибка самого OpenCode, а не вашего ключа, сервера или региона: в версиях 2.0.x форма сохранения не подключена к серверу и выдаёт эту ошибку при любых введённых данных. VPN и смена ключа не помогут. Решение — описать провайдера в файле `opencode.json`: так он работает и в Desktop, и в терминальной версии. Ниже — что именно сломано, готовые конфиги для Claude, GPT и Qwen и что делать, если модели не появились.

    Иконка чипа0
    Иконка глаза247
    Иконка комментариев0
    Картинка поста Как тратить меньше токенов в Claude Code
    Иконка аватараАнтон
    Иконка календаря25 октября 2026
    Claude CodeAnthropicAI-инструментыmiddleИконка уровня middle

    Как тратить меньше токенов в Claude Code

    Чтобы Claude Code тратил меньше токенов, сократите контекст, который он пересылает с каждым запросом, и не ломайте кэш посреди задачи. На практике это пять привычек: `/clear` между несвязанными задачами, `/compact` в паузах, а не посреди работы, Sonnet вместо Opus для повседневного кода, выбор модели в начале сессии, а не на середине, и короткий `CLAUDE.md`. Дороже всего в счёте обходится не длина ваших вопросов, а новый контекст и пересборка кэша — именно их эти привычки и сокращают.

    Иконка чипа0
    Иконка глаза239
    Иконка комментариев0
    Иконка чипа0