Programación funcional en TypeScript: fundamentos y práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Programación funcional en TypeScript: de la teoría a la práctica



La programación funcional (PF) es un paradigma en el que los cómputos se tratan como evaluación de funciones matemáticas y se evita el cambio de estado y los datos mutables. TypeScript, al ser una extensión de JavaScript, es excelente para aplicar los principios de PF gracias a su tipado estricto y soporte para funciones de orden superior. En este artículo analizaremos los conceptos clave de PF en TypeScript y mostraremos cómo aplicarlos en la práctica.



1. Funciones puras e inmutabilidad



Función pura es una función que:

  • Siempre devuelve el mismo resultado para los mismos argumentos (determinismo).
  • No tiene efectos secundarios (no modifica variables externas, no imprime datos, no realiza solicitudes).


Ejemplo de función pura:

// Función pura: suma dos númerosconst add = (a: number, b: number): number => a + b;

// Siempre devolverá 5console.log(add(2, 3)); // 5console.log(add(2, 3)); // 5


Inmutabilidad es el principio por el cual los datos no se modifican después de su creación. En lugar de modificar un objeto existente, se crea uno nuevo.



// Actualización inmutable de un arrayconst numbers: number[] = [1, 2, 3];

// Malo (mutación):numbers.push(4);

// Bueno (inmutable):const newNumbers = [...numbers, 4]; // [1,2,3,4]

// Actualización inmutable de un objetointerface User { name: string; age: number;}

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


2. Composición de funciones y currying



Composición de funciones es la combinación de dos o más funciones en una nueva. El resultado de la primera función se pasa como argumento a la segunda.



// Composición de dos funcionesconst 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 es la transformación de una función con múltiples argumentos en una secuencia de funciones con un solo argumento.



// Función normalconst multiply = (a: number, b: number): number => a * b;

// Versión currificadaconst curriedMultiply = (a: number) => (b: number): number => a * b;

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


El currying facilita la aplicación parcial y la reutilización de funciones.



3. Funtores y mónadas: Maybe y Either



Funtor es un contenedor que implementa el método map, permitiendo aplicar una función al valor dentro del contenedor. En TypeScript, un ejemplo de funtor es el array:



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


Mónada es un funtor que además implementa el método flatMap (o bind) y of (o return). Las mónadas ayudan a manejar efectos secundarios, valores null y errores sin excepciones.



Implementemos una mónada Maybe simple para trabajar de forma segura con null/undefined:



// Mónada Maybeclass 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

Book Recommendations