← Назад к вопросам

Как наследуются от класса в TypeScript?

2.3 Middle🔥 212 комментариев
#JavaScript Core#TypeScript

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Наследование в TypeScript

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

Базовый синтаксис наследования

Для наследования используется ключевое слово extends. Дочерний класс (наследник) получает доступ ко всем публичным (public) и защищенным (protected) членам родительского класса.

// Базовый класс (родительский)
class Animal {
  constructor(public name: string) {}
  
  move(distance: number = 0): void {
    console.log(`${this.name} переместился на ${distance} метров`);
  }
  
  protected breathe(): void {
    console.log(`${this.name} дышит`);
  }
}

// Дочерний класс (наследник)
class Dog extends Animal {
  private breed: string;
  
  constructor(name: string, breed: string) {
    super(name); // Вызов конструктора родительского класса
    this.breed = breed;
  }
  
  bark(): void {
    console.log(`${this.name} породы ${this.breed} лает: Гав!`);
    this.breathe(); // Доступ к protected методу
  }
  
  // Переопределение метода
  move(distance: number = 5): void {
    console.log(`${this.name} бежит`);
    super.move(distance); // Вызов родительского метода
  }
}

// Использование
const myDog = new Dog('Бобик', 'Овчарка');
myDog.move(10); // Бобик бежит \n Бобик переместился на 10 метров
myDog.bark();   // Бобик породы Овчарка лает: Гав! \n Бобик дышит

Ключевые аспекты наследования

1. Конструктор и super()

  • Конструктор дочернего класса обязан вызывать super() до первого обращения к this
  • super позволяет обращаться к родительскому классу
class Vehicle {
  constructor(protected maxSpeed: number) {}
}

class Car extends Vehicle {
  constructor(maxSpeed: number, public brand: string) {
    super(maxSpeed); // Обязательный вызов
    // Теперь можно использовать this
    this.brand = brand;
  }
}

2. Модификаторы доступа

  • public — доступны везде (по умолчанию)
  • protected — доступны в классе и наследниках
  • private — доступны только в классе-владельце
  • readonly — только для чтения
class Base {
  public publicProp = 'public';
  protected protectedProp = 'protected';
  private privateProp = 'private';
  readonly constantProp = 'constant';
}

class Derived extends Base {
  accessCheck() {
    console.log(this.publicProp);     // ✓ Доступно
    console.log(this.protectedProp);  // ✓ Доступно
    // console.log(this.privateProp); // ✗ Ошибка: private
    console.log(this.constantProp);   // ✓ Доступно, но не для записи
  }
}

3. Переопределение методов (Override)

Дочерний класс может переопределять методы родителя, сохраняя или изменяя логику:

class Shape {
  getArea(): number {
    return 0;
  }
  
  getDescription(): string {
    return 'Фигура';
  }
}

class Circle extends Shape {
  constructor(private radius: number) {
    super();
  }
  
  // Полное переопределение
  getArea(): number {
    return Math.PI * this.radius ** 2;
  }
  
  // Расширение родительского метода
  getDescription(): string {
    return `${super.getDescription()}: Круг радиусом ${this.radius}`;
  }
}

Продвинутые возможности

1. Абстрактные классы

TypeScript поддерживает абстрактные классы, которые нельзя инстанциировать напрямую:

abstract class Database {
  abstract connect(): Promise<void>;
  
  protected log(message: string): void {
    console.log(`[DB]: ${message}`);
  }
}

class PostgreSQL extends Database {
  async connect(): Promise<void> {
    this.log('Подключаемся к PostgreSQL...');
    // Реализация подключения
  }
}

// const db = new Database(); // ✗ Ошибка: нельзя создать экземпляр абстрактного класса
const pg = new PostgreSQL(); // ✓ Можно

2. Наследование интерфейсов и реализация

TypeScript поддерживает множественное наследование через интерфейсы:

interface Swimmable {
  swim(): void;
}

interface Flyable {
  fly(): void;
}

class Bird {
  move() {
    console.log('Перемещается');
  }
}

class Duck extends Bird implements Swimmable, Flyable {
  swim(): void {
    console.log('Плавает');
  }
  
  fly(): void {
    console.log('Летает');
  }
}

3. Статические члены и наследование

Статические свойства и методы также наследуются:

class Counter {
  static totalCount: number = 0;
  
  static incrementTotal(): void {
    Counter.totalCount++;
  }
}

class SpecialCounter extends Counter {
  static specialIncrement(): void {
    // Обращение к статическому свойству родителя
    Counter.totalCount += 10;
  }
}

Counter.incrementTotal();
SpecialCounter.specialIncrement();
console.log(Counter.totalCount); // 11

Практические рекомендации

  1. Используйте композицию вместо наследования, где это уместно
  2. Соблюдайте принцип подстановки Барбары Лисков — наследники должны быть взаимозаменяемы с родителями
  3. Избегайте глубоких иерархий наследования (более 2-3 уровней)
  4. Применяйте абстрактные классы для определения общего контракта
  5. Используйте protected вместо private, если планируется расширение класса

Ограничения TypeScript

  • Нет множественного наследования классов (только через интерфейсы)
  • Модификатор private не обеспечивает приватности во время выполнения (только на этапе компиляции)
  • Для истинной инкапсуляции используйте замыкания или новые поля класса с #

Наследование в TypeScript предоставляет мощный инструмент для создания иерархий классов, повторного использования кода и построения сложных объектных моделей, сочетая при этом строгую типизацию и современные возможности ООП.