Funktionale Programmierung in TypeScript: Fortgeschrittenes Niveau

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: Fortgeschrittenes Niveau

\n\n

Funktionale Programmierung (FP) ist ein Paradigma, das Berechnungen als Auswertung mathematischer Funktionen betrachtet und Zustandsänderungen sowie veränderliche Daten vermeidet. TypeScript, als Erweiterung von JavaScript, bietet ein leistungsstarkes Typsystem, das es ermöglicht, viele FP-Konzepte auf einem neuen Niveau von Sicherheit und Ausdrucksstärke umzusetzen. In diesem Artikel betrachten wir fortgeschrittene Techniken: von strenger Unveränderlichkeit bis zur Arbeit mit Monaden und Funktoren.

\n\n

Unveränderlichkeit und Arbeit mit unveränderlichen Strukturen

\n\n

Unveränderlichkeit (Immutability) ist ein Eckpfeiler der FP. In TypeScript können wir sie auf Typebene mit Hilfe der Modifikatoren readonly und utilitären Typen garantieren.

\n\n
// Tiefe Unveränderlichkeit durch ReadonlyDeep\ntype DeepReadonly<T> = {\n  readonly [P in keyof T]: DeepReadonly<T[P]>;\n};\n\ninterface User {\n  name: string;\n  address: { city: string; zip: number };\n}\n\nconst user: DeepReadonly<User> = {\n  name: "Alice",\n  address: { city: "Moscow", zip: 101000 }\n};\n\n// user.address.city = "SPb"; // Fehler! Eigenschaft ist schreibgeschützt
\n\n

Verwenden Sie für sicheres Aktualisieren von Daten reine Funktionen, die neue Objekte zurückgeben:

\n\n
function updateZip(user: DeepReadonly<User>, newZip: number): DeepReadonly<User> {\n  return { ...user, address: { ...user.address, zip: newZip } };\n}\n\nconst updatedUser = updateZip(user, 190000);
\n\n

Funktionskomposition und Currying

\n\n

Komposition ermöglicht es, komplexe Transformationen aus einfachen Funktionen aufzubauen. In TypeScript können wir mit Hilfe von Generics typsichere Kombinatoren erstellen.

\n\n
// Typ für die Komposition zweier Funktionen\ntype Compose<A, B, C> = (f: (b: B) => C, g: (a: A) => B) => (a: A) => C;\n\nconst compose: Compose<any, any, any> = (f, g) => (x) => f(g(x));\n\n// Beispiel: Umwandlung eines Strings in eine Zahl und Erhöhung um 1\nconst toNumber = (s: string): number => parseInt(s, 10);\nconst increment = (n: number): number => n + 1;\n\nconst parseAndIncrement = compose(increment, toNumber);\nconsole.log(parseAndIncrement("5")); // 6
\n\n

Currying verwandelt eine Funktion mit mehreren Argumenten in eine Folge von Funktionen mit einem Argument. Dies macht die Komposition flexibler:

\n\n
// Universelle Curry-Funktion mit Typen\nfunction curry<T1, T2, R>(fn: (a: T1, b: T2) => R): (a: T1) => (b: T2) => R {\n  return (a: T1) => (b: T2) => fn(a, b);\n}\n\nconst add = (a: number, b: number): number => a + b;\nconst curriedAdd = curry(add);\nconst add5 = curriedAdd(5);\nconsole.log(add5(3)); // 8
\n\n

Funktoren und Monaden: Arbeit mit Kontexten

\n\n

Funktor ist eine Datenstruktur, die die Operation map unterstützt. In TypeScript kann ein Array, Promise oder ein benutzerdefinierter Typ ein Funktor sein.

\n\n
// Funktor Option (Maybe) für sicheres Arbeiten mit null/undefined\ninterface Option<T> {\n  map<U>(fn: (value: T) => U): Option<U>;\n  getOrElse(defaultValue: T): T;\n}\n\nclass Some<T> implements Option<T> {\n  constructor(private value: T) {}\n  map<U>(fn: (value: T) => U): Option<U> {\n    return new Some(fn(this.value));\n  }\n  getOrElse(_: T): T {\n    return this.value;\n  }\n}\n\nclass None<T> implements Option<T> {\n  map<U>(_: (value: T) => U): Option<U> {\n    return new None<U>();\n  }\n  getOrElse(defaultValue: T): T {\n    return defaultValue;\n  }\n}\n\n// Verwendung\nconst maybeNumber: Option<number> = new Some(42);\nconst result = maybeNumber.map(x => x * 2).getOrElse(0); // 84
\n\n

Monade erweitert den Funktor um die Methode flatMap (oder bind

Blogs

Buchempfehlungen