Funktionale Programmierung in TypeScript: Grundlagen und Praxis

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Funktionale Programmierung in TypeScript: Von der Theorie zur Praxis



Funktionale Programmierung (FP) ist ein Paradigma, bei dem Berechnungen als Auswertung mathematischer Funktionen behandelt werden und Zustandsänderungen sowie veränderliche Daten vermieden werden. TypeScript, als Erweiterung von JavaScript, eignet sich hervorragend für die Anwendung von FP-Prinzipien dank seiner strengen Typisierung und Unterstützung für Funktionen höherer Ordnung. In diesem Artikel werden wir die wichtigsten Konzepte der FP in TypeScript durchgehen und zeigen, wie man sie in der Praxis anwendet.



1. Reine Funktionen und Unveränderlichkeit (Immutability)



Eine reine Funktion ist eine Funktion, die:

  • Für dieselben Argumente immer dasselbe Ergebnis zurückgibt (Determinismus).
  • Keine Seiteneffekte hat (keine externen Variablen ändert, keine Daten ausgibt, keine Anfragen stellt).


Beispiel einer reinen Funktion:

// Reine Funktion: Addiert zwei Zahlenconst add = (a: number, b: number): number => a + b;

// Gibt immer 5 zurückconsole.log(add(2, 3)); // 5console.log(add(2, 3)); // 5


Unveränderlichkeit (Immutability) ist das Prinzip, dass Daten nach ihrer Erstellung nicht mehr geändert werden. Statt ein bestehendes Objekt zu ändern, wird ein neues erstellt.



// Unveränderliches (immutables) Aktualisieren eines Arraysconst numbers: number[] = [1, 2, 3];

// Schlecht (Mutation):numbers.push(4);

// Gut (unveränderlich):const newNumbers = [...numbers, 4]; // [1,2,3,4]

// Unveränderliches Aktualisieren eines Objektsinterface User { name: string; age: number;}

const user: User = { name: 'Alice', age: 30 };const updatedUser: User = { ...user, age: 31 }; // neues Objekt


2. Funktionskomposition und Currying



Funktionskomposition ist die Kombination von zwei oder mehr Funktionen zu einer neuen. Das Ergebnis der ersten Funktion wird als Argument an die zweite übergeben.



// Komposition zweier Funktionenconst compose = <T, U, V>(f: (x: U) => V, g: (x: T) => U) =>  (x: T): V => f(g(x));

const double = (x: number): number => x * 2;const increment = (x: number): number => x + 1;

const doubleThenIncrement = compose(increment, double);console.log(doubleThenIncrement(3)); // (3*2)+1 = 7


Currying ist die Umwandlung einer Funktion mit mehreren Argumenten in eine Folge von Funktionen mit jeweils einem Argument.



// Normale Funktionconst multiply = (a: number, b: number): number => a * b;

// Curry-Versionconst curriedMultiply = (a: number) => (b: number): number => a * b;

const multiplyBy2 = curriedMultiply(2);console.log(multiplyBy2(5)); // 10console.log(multiplyBy2(7)); // 14


Currying vereinfacht die partielle Anwendung und Wiederverwendung von Funktionen.



3. Funktoren und Monaden: Maybe und Either



Ein Funktor ist ein Container, der eine map-Methode implementiert, mit der eine Funktion auf den Wert im Container angewendet werden kann. In TypeScript ist ein Array beispielsweise ein Funktor:



const numbers = [1, 2, 3];const doubled = numbers.map(x => x * 2); // [2, 4, 6]


Eine Monade ist ein Funktor, der zusätzlich die Methoden flatMap (oder bind) und of (oder return) implementiert. Monaden helfen bei der Behandlung von Seiteneffekten, Null-Werten und Fehlern ohne Ausnahmen.



Wir implementieren eine einfache Maybe-Monade für die sichere Arbeit mit null/undefined:



// Maybe Monadeclass Maybe<T> {  private constructor(private value: T | null) {}

static of<T>(value: T): Maybe<T> { return new Maybe(value); }

static none<T>(): Maybe<T> { return new Maybe<T>(null); }

map<U>(fn: (value: T) => U): Maybe<U> { if (this.value === null || this.value === undefined) { return Maybe.none(); } return M

Blogs

Buchempfehlungen