Static Members, Getters, and Setters in TypeScript
Static Members, Getters, and Setters
~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
To wrap up Phase 3 (object-oriented programming): two tools enabling INSTANCE-independent functionality (static) and controlled property access with normal dot syntax (get/set).
Static members: belong to the class, not the instance
export class Library {
private static nextId = 1; // belongs to the CLASS, not to a single library
public readonly id: number;
private stock: Book[];
constructor(initialStock: Book[]) {
this.id = Library.nextId++; // access via the class name, not 'this'
this.stock = initialStock;
}
}
const a = new Library([]);
const b = new Library([]);
console.log(a.id, b.id); // 1, 2 - each instance gets a UNIQUE, sequential IDstatic nextId exists EXACTLY ONCE, shared by ALL instances of Library – unlike stock, which EVERY instance has its own copy of. Access happens via Library.nextId (the class name), NOT this.nextId.
Static methods: utility functions bound to the class
export class Book {
// ... existing properties
static isValidIsbn(isbn: string): boolean {
const cleaned = isbn.replace(/-/g, '');
return cleaned.length === 13 && /^\d+$/.test(cleaned);
}
}
Book.isValidIsbn('978-0-618-64015-7'); // true - CALLED via the class name, no instance neededstatic isValidIsbn(...) needs NO Book instance to be called – useful for helper functions that logically BELONG to a class (ISBN validation is a "book" concept), but don't need access to this.
Getters and setters: computed properties with dot syntax
export class Book extends Medium {
private _pageCount: number;
constructor(/* ... */ pageCount: number) {
super(/* ... */);
this._pageCount = pageCount;
}
get pageCount(): number {
return this._pageCount;
}
set pageCount(value: number) {
if (value <= 0) {
throw new Error('Page count must be positive.');
}
this._pageCount = value;
}
get readingTimeMinutes(): number {
return Math.round(this._pageCount * 1.5); // COMPUTED value, not a real property
}
}
const book = new Book(/* ... */ 300);
console.log(book.pageCount); // 300 - reads like a regular property, but calls the GETTER
book.pageCount = 350; // writes like a regular property, calls the SETTER
book.pageCount = -10; // throws the Error from the setter
console.log(book.readingTimeMinutes); // 450 - ONLY a getter, no matching setter -> read-onlyFrom OUTSIDE, book.pageCount looks like an ORDINARY property (no parentheses like a method call!) – INTERNALLY, your own code runs on every read/write. The leading underscore _pageCount is a pure NAMING CONVENTION (not TypeScript-specific), to distinguish the "real", private data storage from the public getter/setter pair.
Only a getter: automatically read-only
readingTimeMinutes has ONLY a get, NO set – trying book.readingTimeMinutes = 100 would trigger a compile-time error. That's a MORE ELEGANT equivalent to readonly from chapter 7/11 for values that are COMPUTED instead of stored.
Achtung: Getters/setters feel "magic", but be careful with EXCESSIVE logic inside them – a getter that does expensive computations or even network calls surprises callers who assume book.pageCount is a simple, cheap property read. Rule of thumb: getters/setters for SIMPLE validation and light computation, real asynchronous/expensive operations belong in explicitly named methods.
Tipp: That wraps up Phase 3 (OOP) – classes, inheritance, access modifiers, abstract classes, static members, getters/setters. Phase 4 turns to the GENUINELY advanced TypeScript features, starting with generics – the tool that makes our somewhat repetitive Library class REUSABLE for ANY medium type, not just books.