Programmation fonctionnelle en TypeScript : niveau avancé

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Programmation fonctionnelle en TypeScript : niveau avancé

\n\n

La programmation fonctionnelle (PF) est un paradigme qui considère le calcul comme l'évaluation de fonctions mathématiques et évite les changements d'état et les données mutables. TypeScript, étant une surcouche de JavaScript, fournit un système de types puissant qui permet d'implémenter de nombreux concepts de la PF à un nouveau niveau de sécurité et d'expressivité. Dans cet article, nous examinerons les techniques avancées : de l'immutabilité stricte au travail avec les monades et les foncteurs.

\n\n

Immutabilité et travail avec des structures immuables

\n\n

L'immutabilité (caractère immuable) est la pierre angulaire de la PF. En TypeScript, nous pouvons la garantir au niveau des types à l'aide des modificateurs readonly et des types utilitaires.

\n\n
// Immuabilité profonde avec 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"; // Erreur ! Propriété en lecture seule
\n\n

Pour mettre à jour les données en toute sécurité, utilisez des fonctions pures qui retournent de nouveaux objets :

\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

Composition de fonctions et curryfication

\n\n

La composition permet de construire des transformations complexes à partir de fonctions simples. En TypeScript, à l'aide des génériques, nous pouvons créer des combinateurs typés de manière sécurisée.

\n\n
// Type pour la composition de deux fonctions\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// Exemple : transformer une chaîne en nombre et l'incrémenter de 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

La curryfication transforme une fonction à plusieurs arguments en une séquence de fonctions à un seul argument. Cela rend la composition plus flexible :

\n\n
// Fonction de curryfication universelle avec types\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

Foncteurs et monades : travailler avec des contextes

\n\n

Un foncteur est une structure de données qui prend en charge l'opération map. En TypeScript, un tableau, une Promise ou un type personnalisé peuvent être des foncteurs.

\n\n
// Foncteur Option (Maybe) pour travailler en toute sécurité avec 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// Utilisation\nconst maybeNumber: Option<number> = new Some(42);\nconst result = maybeNumber.map(x => x * 2).getOrElse(0); // 84
\n\n

Une monade étend le foncteur avec la méthode flatMap (ou bind

Blogs

Book Recommendations