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
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
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 missingAchtung: 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-onlyreadonly 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
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.