Что такое abstract class в TypeScript?

MiddleTypeScript · Frontend·Обновлено 31 июля 2026
Коротко
Abstract class — это базовый класс, который нельзя инстанциировать напрямую; он задаёт общий контракт и может содержать как абстрактные методы (без реализации), так и конкретные методы с реализацией.

Abstract class в TypeScript

Абстрактный класс (abstract class) — это специальный вид класса, который служит базой для других классов, но не может быть создан напрямую с помощью new. Он позволяет описать общий интерфейс и частичную реализацию, которую наследники обязаны дополнить.

Ключевые характеристики

  • Нельзя инстанциировать напрямую — попытка вызвать new AbstractClass() вызовет ошибку компиляции.
  • Может содержать абстрактные методы — методы с ключевым словом abstract без тела; наследник обязан их реализовать.
  • Может содержать конкретные методы — обычные методы с готовой реализацией, которые наследники могут использовать или переопределить.
  • Может содержать поля и конструктор — в отличие от интерфейса, абстрактный класс поддерживает состояние и инициализационную логику.

Абстрактный класс vs интерфейс

Интерфейс описывает только форму объекта и существует только на уровне типов (стирается при компиляции). Абстрактный класс компилируется в реальный JavaScript-класс, может хранить состояние, содержать конструктор и логику, а также использоваться с instanceof.

Выбирайте абстрактный класс, когда нужно:

  • Определить общее состояние или конструктор для группы классов.
  • Предоставить готовую реализацию части методов (шаблонный метод).
  • Выразить отношение «является» (is-a) с частичной логикой.

Выбирайте интерфейс, когда нужно описать только контракт без реализации или когда класс должен реализовать несколько контрактов одновременно.

Паттерн «Шаблонный метод»

Абстрактный класс отлично подходит для паттерна Template Method: базовый класс определяет алгоритм в виде конкретного метода, а шаги алгоритма делегируются абстрактным методам, которые переопределяют наследники.

Важные нюансы

  • Абстрактный метод автоматически является public (или может быть protected), но не private.
  • Наследник должен реализовать все абстрактные методы, иначе он тоже должен быть объявлен абстрактным.
  • Абстрактные классы поддерживают generics, access modifiers и readonly.

Что хочет услышать интервьюер

Понимание того, что abstract class нельзя инстанциировать напрямую и зачем это нужно

Различие между абстрактными методами (без реализации) и конкретными методами (с реализацией) внутри абстрактного класса

Осознанное сравнение abstract class и interface: когда выбрать одно, а когда другое

Знание того, что наследник обязан реализовать все абстрактные методы или сам стать абстрактным

Практический пример применения — например, паттерн Template Method или базовый класс для группы сущностей

Пример: Базовый пример абстрактного класса

abstract class Shape {
  // Абстрактный метод — наследник обязан реализовать
  abstract getArea(): number;

  // Конкретный метод — готовая реализация для всех наследников
  describe(): string {
    return `Площадь фигуры: ${this.getArea()}`;
  }
}

class Circle extends Shape {
  constructor(private radius: number) {
    super();
  }

  // Реализуем обязательный абстрактный метод
  getArea(): number {
    return Math.PI * this.radius ** 2;
  }
}

class Rectangle extends Shape {
  constructor(private width: number, private height: number) {
    super();
  }

  getArea(): number {
    return this.width * this.height;
  }
}

// const shape = new Shape(); // Ошибка: Cannot create an instance of an abstract class
const circle = new Circle(5);
console.log(circle.describe()); // Площадь фигуры: 78.53...

Пример: Паттерн Template Method

abstract class DataExporter {
  // Шаблонный метод — задаёт алгоритм экспорта
  export(data: unknown[]): string {
    const filtered = this.filter(data);
    const transformed = this.transform(filtered);
    return this.serialize(transformed);
  }

  // Шаги алгоритма — наследники определяют детали
  protected abstract filter(data: unknown[]): unknown[];
  protected abstract transform(data: unknown[]): unknown[];
  protected abstract serialize(data: unknown[]): string;
}

class CsvExporter extends DataExporter {
  protected filter(data: unknown[]): unknown[] {
    // Фильтруем пустые строки
    return (data as string[]).filter(Boolean);
  }

  protected transform(data: unknown[]): unknown[] {
    return (data as string[]).map(s => s.trim());
  }

  protected serialize(data: unknown[]): string {
    return (data as string[]).join(',');
  }
}

const exporter = new CsvExporter();
console.log(exporter.export(['Alice', '', ' Bob', 'Carol']));
// Alice,Bob,Carol

Пример: Abstract class vs Interface

// Интерфейс — только контракт, без реализации, без состояния
interface Logger {
  log(message: string): void;
}

// Абстрактный класс — контракт + общая реализация + состояние
abstract class BaseLogger implements Logger {
  private readonly prefix: string;

  constructor(prefix: string) {
    this.prefix = prefix;
  }

  // Конкретный метод использует абстрактный
  log(message: string): void {
    this.write(`[${this.prefix}] ${message}`);
  }

  // Каждый наследник решает, куда писать
  protected abstract write(line: string): void;
}

class ConsoleLogger extends BaseLogger {
  protected write(line: string): void {
    console.log(line);
  }
}

class FileLogger extends BaseLogger {
  protected write(line: string): void {
    // Запись в файл
    process.stdout.write(line + '\n');
  }
}

const logger: Logger = new ConsoleLogger('APP');
logger.log('Старт'); // [APP] Старт

Типичные ошибки

Путают abstract class с interface, не понимая, что abstract class компилируется в JS-код и может хранить состояние

Думают, что в abstract class все методы должны быть абстрактными, забывая о возможности конкретных реализаций

Не знают, что попытка создать экземпляр abstract class — это ошибка на этапе компиляции TypeScript, а не рантайма

Забывают, что наследник должен реализовать все abstract-методы, иначе TypeScript выдаст ошибку

Используют abstract class там, где достаточно interface, добавляя лишнюю иерархию наследования

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

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

TypeScript с нуля

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

Feature-Sliced Design

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

Next.js - с нуля

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