Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Interfaces in TypeScript

Interfaces

~15 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

Time to finally consolidate the loose variables from chapter 4 into a clean Book type. Interfaces are TypeScript's main tool for naming and reusing an object's SHAPE.

The first interface: Book

src/models/Book.ts
export interface Book {
  isbn: string;
  title: string;
  author: string;
  publicationYear: number;
  pageCount: number;
  genres: string[];
  isBorrowed: boolean;
}

export makes the interface importable from other files (covered in detail in chapter 24, modules) – from now on, we'll place every significant type in its OWN file under src/models/, instead of piling everything into index.ts.

Using the interface

src/index.ts
import { Book } from './models/Book.js';
// Notice the '.js' extension in the import, EVEN THOUGH the file is called
// 'Book.ts' - this is a quirk of "NodeNext" module resolution from chapter 3:
// imports reference the COMPILED filename, not the source filename.

const lordOfTheRings: Book = {
  isbn: '978-0-618-64015-7',
  title: 'The Lord of the Rings',
  author: 'J.R.R. Tolkien',
  publicationYear: 1954,
  pageCount: 1216,
  genres: ['Fantasy', 'Adventure'],
  isBorrowed: false,
};

console.log(`${lordOfTheRings.title} by ${lordOfTheRings.author}`);

const bookWithoutAuthor: Book = {
  isbn: '123',
  title: 'Test',
  publicationYear: 2024,
  pageCount: 100,
  genres: [],
  isBorrowed: false,
}; // error: property 'author' is missing

Achtung: An object assigned to an interface must have ALL of the interface's properties, with the CORRECT types – if a property is missing or has the wrong type, TypeScript IMMEDIATELY shows a precise error with the name of the missing/wrong property.

Optional properties

export interface Book {
  isbn: string;
  title: string;
  author: string;
  publicationYear: number;
  pageCount: number;
  genres: string[];
  isBorrowed: boolean;
  coverImageUrl?: string; // optional - not every book has a cover image on file
}

EXACTLY the same ? syntax as optional function parameters (chapter 6) – coverImageUrl can be omitted when creating a Book object, but has the type string | undefined inside the code.

readonly: immutable properties

export interface Book {
  readonly isbn: string; // an ISBN NEVER changes after creation
  title: string;
  // ... rest as before
}

lordOfTheRings.isbn = '999'; // error: isbn is read-only

readonly prevents CHANGES after the object is created – useful for properties that conceptually represent a fixed identity (like an ISBN), unlike properties that SHOULD change over an object's lifetime (like isBorrowed).

Nested interfaces: Author as its own type

src/models/Author.ts
export interface Author {
  name: string;
  birthYear: number;
  nationality: string;
}
// In Book.ts:
import { Author } from './Author.js';

export interface Book {
  readonly isbn: string;
  title: string;
  author: Author; // the full Author object instead of just a string now
  publicationYear: number;
  pageCount: number;
  genres: string[];
  isBorrowed: boolean;
  coverImageUrl?: string;
}

Interfaces can contain ANY other types as properties, including other interfaces – author: Author is now a full, SEPARATE object instead of a plain string, with its own type checking for name/birthYear/nationality.

Extending interfaces with extends

export interface Person {
  name: string;
  birthYear: number;
}

export interface Author extends Person {
  nationality: string;
  knownWorks: string[];
}

export interface Member extends Person {
  memberNumber: string;
  borrowedBooks: string[]; // ISBNs
}

extends inherits ALL properties of the base interface and adds new ones – EXACTLY like class inheritance (chapter 13), just for pure type definitions with no implementation. Author and Member share name/birthYear from Person, without rewriting those fields in EVERY interface.

Tipp: Rule of thumb: once an object shape is used in MORE THAN ONE place in the code (a function expects it, several variables have it), a named interface is worth it – for purely ONE-OFF, local objects (like our CompareFunction example from chapter 6), the inline type inference from chapter 5 is often sufficient.