Inheritance in TypeScript
Inheritance
~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
Our library should also manage AUDIOBOOKS alongside regular books – with almost the same properties, but a runtime length instead of a page count. Inheritance avoids duplicating the shared code.
A shared base class: Medium
import { Author } from './Author.js';
import { Genre } from './Genre.js';
import { BookStatus } from './Book.js';
export class Medium {
constructor(
public readonly isbn: string,
public title: string,
public author: Author,
public publicationYear: number,
public genres: Genre[],
public status: BookStatus,
) {}
description(): string {
return `${this.title} by ${this.author.name} (${this.publicationYear})`;
}
}Medium uses constructor property promotion from chapter 12 for ALL shared properties – deliberately a CLASS instead of an interface, since we already want to bundle BEHAVIOR (description()) with the data, shared by ALL derived types.
Book and Audiobook as derived classes
import { Medium } from './Medium.js';
import { Author } from './Author.js';
import { Genre } from './Genre.js';
export type BookStatus = 'available' | 'borrowed' | 'reserved';
export class Book extends Medium {
constructor(
isbn: string,
title: string,
author: Author,
publicationYear: number,
genres: Genre[],
status: BookStatus,
public pageCount: number,
) {
super(isbn, title, author, publicationYear, genres, status);
}
}import { Medium } from './Medium.js';
import { Author } from './Author.js';
import { Genre } from './Genre.js';
import { BookStatus } from './Book.js';
export class Audiobook extends Medium {
constructor(
isbn: string,
title: string,
author: Author,
publicationYear: number,
genres: Genre[],
status: BookStatus,
public runtimeMinutes: number,
public narrator: string,
) {
super(isbn, title, author, publicationYear, genres, status);
}
// overrides the inherited method with an extended version
override description(): string {
return `${super.description()}, narrated by ${this.narrator}`;
}
}extends, super, and override in detail
extends Medium–Book/AudiobookINHERIT ALL properties and methods ofMedium, without rewriting them.super(...)– MUST be called as the FIRST statement in a derived class's constructor, calls the BASE class's constructor to initialize the inherited properties.override description()– REPLACES the inherited method with a custom implementation. Theoverridekeyword is an explicit STATEMENT OF INTENT: "I'm deliberately overriding an inherited method" – TypeScript shows an error ifMediumhad NO method calleddescriptionat all (typo protection).super.description()– calls the ORIGINAL, inherited version of the method beforeAudiobookAPPENDS its own text – reuse instead of duplication.
Polymorphism: treating different media uniformly
const media: Medium[] = [
new Book('123', 'The Hobbit', tolkien, 1937, ['Fantasy'], 'available', 310),
new Audiobook('456', 'The Hobbit', tolkien, 1937, ['Fantasy'], 'available', 620, 'Rob Inglis'),
];
media.forEach((medium) => console.log(medium.description()));
// Book uses the INHERITED description(), Audiobook the OVERRIDDEN one -
// same call, different behavior, depending on the ACTUAL typemedia: Medium[] can hold BOTH types, because Book AND Audiobook both ARE Medium (an "is-a" relationship) – that's EXACTLY "polymorphism": the same method call (description()) behaves differently depending on the actual object type, without the calling code having to check that itself.
Achtung: Inheritance is powerful, but easy to OVEREXTEND – deep inheritance hierarchies (A extends B extends C extends D) quickly become unwieldy. Rule of thumb: use inheritance only for GENUINE "is-a" relationships (an audiobook IS a medium), NOT for pure code reuse with no conceptual relationship – other patterns exist for that (composition), beyond the scope of this chapter.