TypeScript

TypeScript

Tutorial TypeScript: Composición de funciones

Aprende la composición de funciones en TypeScript para crear código modular y reutilizable con ejemplos prácticos de pipe y compose.

Aprende TypeScript y certifícate

Concepto de composición funcional

La composición de funciones es uno de los pilares fundamentales de la programación funcional. Este concepto proviene directamente de las matemáticas, donde se define como la aplicación de una función al resultado de otra. En términos simples, es una técnica que nos permite combinar múltiples funciones para crear una nueva función más compleja.

Imagina que tienes dos funciones: una que convierte un texto a mayúsculas y otra que elimina espacios. La composición te permitiría crear una nueva función que realice ambas operaciones de manera secuencial, aplicando primero una y luego la otra al resultado.

¿Qué es la Composición Funcional?

La composición de funciones es una técnica que consiste en combinar dos o más funciones para crear una nueva función. El resultado de una función se convierte en la entrada de la siguiente, creando un flujo de datos continuo. Este concepto proviene directamente de las matemáticas, donde se define como la aplicación de una función al resultado de otra.

En matemáticas, la composición de funciones se representa como (f∘g)(x), que significa "f compuesta con g". Se evalúa como f(g(x)), es decir, primero se aplica g a x, y luego se aplica f al resultado de g(x).

Ejemplo Básico (Composición Manual): Imagina que tienes dos funciones simples: una que duplica un número y otra que le suma uno.

// Dos funciones simples
const double = (x: number): number => x * 2;
const addOne = (x: number): number => x + 1;

// Composición manual
const doubleAndAddOne = (x: number): number => addOne(double(x));


console.log(doubleAndAddOne(3)); // Resultado: 7 (primero 3*2=6, luego 6+1=7)

En este ejemplo, doubleAndAddOne es una nueva función que combina el comportamiento de double y addOne.

Ventajas de la composición funcional

La composición de funciones no es solo una curiosidad matemática; ofrece ventajas significativas en el desarrollo de software:

  • Modularidad: Fomenta la creación de funciones pequeñas y especializadas que hacen una sola cosa bien. Esto hace que cada pieza de código sea más fácil de entender y probar de forma aislada.
  • Reutilización: Estas funciones pequeñas y puras son como "bloques de construcción" que pueden combinarse de diferentes maneras para crear nuevas funcionalidades sin tener que reescribir código.
  • Legibilidad: El código se vuelve más declarativo y fácil de razonar. En lugar de describir cómo se llega a un resultado (paso a paso), la composición expresa qué se está haciendo (una secuencia de transformaciones).
  • Mantenibilidad: Es más fácil depurar y modificar funciones pequeñas y bien definidas que grandes bloques de código con lógica compleja.

Dirección de la Composición: compose vs pipe

Un aspecto importante a entender es la dirección en la que fluyen los datos durante la composición.

  • compose (Derecha a Izquierda): Sigue la notación matemática estándar (f∘g)(x), donde las funciones se aplican de derecha a izquierda (primero g, luego f).
// Implementación simple de 'compose' para dos funciones
const compose = <A, B, C>(f: (b: B) => C, g: (a: A) => B) => 
  (x: A): C => f(g(x));

// Usando el ejemplo anterior
const doubleAndAddOneCompose = compose(addOne, double);
console.log(doubleAndAddOneCompose(3)); // 7 (double(3) -> 6, addOne(6) -> 7)
  • pipe (Izquierda a Derecha): En programación, a menudo resulta más intuitivo leer el flujo de datos de izquierda a derecha, como una "tubería" o "pipeline". La función pipe invierte el orden de composición para facilitar esta lectura.
// Implementación simple de 'pipe' para dos funciones
const pipe = <A, B, C>(g: (a: A) => B, f: (b: B) => C) => 
  (x: A): C => f(g(x));

// Usando el ejemplo anterior
const doubleAndAddOnePipe = pipe(double, addOne);
console.log(doubleAndAddOnePipe(3)); // 7 (double(3) -> 6, addOne(6) -> 7)

Aunque para dos funciones la implementación se vea igual, la diferencia conceptual es importante para la legibilidad cuando componemos más funciones. La función pipe es generalmente preferida en JavaScript/TypeScript por su fluidez de lectura con el flujo de datos.

Implementación Práctica de la Composición

Para construir composiciones más complejas, especialmente cuando necesitamos encadenar más de dos funciones, implementamos versiones más robustas de pipe y compose que aceptan un número variable de argumentos, a menudo utilizando el método reduce de arrays.

Implementación de pipe para Múltiples Funciones

La función pipe es ideal para construir pipelines donde el resultado de una función se pasa a la siguiente. Utilizaremos Array.prototype.reduce() para encadenar las funciones de izquierda a derecha.

/**
 * Compone una secuencia de funciones de izquierda a derecha.
 * El resultado de cada función se pasa como argumento a la siguiente.
 * @param fns Un array de funciones a componer.
 * Cada función (excepto la última) debe tener un tipo de retorno
 * compatible con el tipo de argumento de la siguiente función.
 * @returns Una nueva función que toma un valor inicial y lo pasa
 * a través de todas las funciones en secuencia.
 */
function pipe<TArgs extends any[], R>(
  ...fns: { 
    [K in keyof TArgs]: K extends '0' 
      ? (arg: TArgs[0]) => TArgs[1] 
      : K extends string
        ? (arg: TArgs[number]) => TArgs[number]
        : never
  } & { length: TArgs['length'] } & Array<(...args: any[]) => any>
): (initialValue: TArgs[0]) => R;

// Implementación concreta para casos comunes (simplificado para evitar tipos genéricos muy complejos)
// En la práctica, TypeScript puede inferir esto para la mayoría de los casos,
// o se usarían sobrecargas para una tipado más estricto en escenarios complejos.
function pipe<T>(...fns: Array<(arg: T) => T>): (value: T) => T {
  return (value) => fns.reduce((acc, fn) => fn(acc), value);
}

// Ejemplo de uso con múltiples transformaciones de datos
const removeSpaces = (text: string): string => text.replace(/\s/g, '');
const toLowerCase = (text: string): string => text.toLowerCase();
const countChars = (text: string): number => text.length;

// Creamos un pipeline para procesar texto
const countCharsNoSpacesAndLowercase = pipe(
  toLowerCase,    // Primero convierte el texto a minúsculas
  removeSpaces,   // Luego elimina todos los espacios
  countChars      // Finalmente cuenta los caracteres restantes
);

const textInput = "Hello TypeScript World";
console.log(`Texto original: "${textInput}"`);
console.log(`Resultado: ${countCharsNoSpacesAndLowercase(textInput)}`); // Salida: 19 (todos en minúsculas, sin espacios)

// Otro ejemplo más complejo
const processTextForSearch = pipe(
  removeSpaces,
  toLowerCase,
  (text: string) => text.replace(/[^a-z0-9]/g, ''), // Elimina caracteres no alfanuméricos
  (text: string) => text.slice(0, 10) // Limita a 10 caracteres
);

const searchInput = "My Awesome Project Name!";
console.log(`Entrada búsqueda: "${searchInput}"`);
console.log(`Texto procesado para búsqueda: "${processTextForSearch(searchInput)}"`); // Salida: "myawesomep"

Nota sobre el tipado: La implementación de pipe y compose con tipos genéricos para manejar flujos de datos donde el tipo de retorno de una función es el tipo de entrada de la siguiente puede ser compleja. Para esta lección, nos centramos en la implementación común donde las funciones operan sobre el mismo tipo de datos ((arg: T) => T). En TypeScript real, se pueden usar técnicas avanzadas de sobrecarga o bibliotecas que ya manejen este tipado complejo para usted.

Implementación de compose para Múltiples Funciones

Similar a pipe, podemos implementar una versión de compose que acepte múltiples funciones. La diferencia clave es que compose aplica las funciones de derecha a izquierda, lo que significa que la última función en el array se ejecuta primero. Esto se logra usando Array.prototype.reduceRight().

/**
 * Compone una secuencia de funciones de derecha a izquierda.
 * El resultado de cada función se pasa como argumento a la anterior.
 * @param fns Un array de funciones a componer.
 * @returns Una nueva función que toma un valor inicial y lo pasa
 * a través de todas las funciones en secuencia (de derecha a izquierda).
 */
function compose<T>(...fns: Array<(arg: T) => T>): (value: T) => T {
  return (value) => fns.reduceRight((acc, fn) => fn(acc), value);
}

// Ejemplo de uso
const doubleNum = (n: number): number => n * 2;
const squareNum = (n: number): number => n * n;
const addFiveNum = (n: number): number => n + 5;

// Composición de múltiples funciones (addFive(square(double(3))))
const complexCalculationCompose = compose(
  addFiveNum,  // Se aplica al final
  squareNum,   // Se aplica en segundo lugar
  doubleNum    // Se aplica primero
);

console.log(`Calculo complejo de 3 (compose): ${complexCalculationCompose(3)}`); // Salida: 41 (3 -> double(3)=6 -> square(6)=36 -> addFive(36)=41)

La elección entre pipe y compose es a menudo una cuestión de preferencia y legibilidad para el equipo. pipe es más popular por su flujo de lectura de izquierda a derecha, que coincide con la forma en que leemos el código.

Patrones y Aplicaciones de la Composición

La composición funcional es una herramienta poderosa para organizar la lógica de nuestro programa, especialmente en el procesamiento de datos y la construcción de pipelines.

Aplicaciones Clave de la Composición (Flujo de Datos)

La composición brilla al construir flujos de procesamiento de datos, donde los datos se someten a una serie de transformaciones.

Transformaciones Secuenciales de Datos

Podemos crear funciones de procesamiento complejas a partir de otras más simples, haciendo el código muy declarativo.

// Funciones de transformación de usuario
interface User {
  id: number;
  name: string;
  email: string;
  isActive: boolean;
}

const normalizeEmail = (user: User): User => ({
  ...user,
  email: user.email.toLowerCase().trim()
});

const formatUsername = (user: User): User => ({
  ...user,
  name: user.name.charAt(0).toUpperCase() + user.name.slice(1).toLowerCase()
});

const validateEmail = (user: User): User => {
  if (!user.email.includes('@')) {
    throw new Error(`Invalid email format for user ${user.id}`);
  }
  return user;
};

// Composición para procesar usuarios
const processUser = pipe(
  normalizeEmail,  // Limpiar y poner email en minúsculas
  validateEmail,   // Validar formato de email (puede lanzar error)
  formatUsername   // Poner primera letra del nombre en mayúscula y resto en minúsculas
);

// Uso
const rawUser = { id: 1, name: "jOHN doe", email: " JOHN.DOE@example.com ", isActive: true };
try {
  const processedUser = processUser(rawUser);
  console.log("Usuario procesado:", processedUser);
  // Salida: { id: 1, name: "John doe", email: "john.doe@example.com", isActive: true }
} catch (error: any) {
  console.error("Error al procesar usuario:", error.message);
}

const invalidUser = { id: 2, name: "jane", email: "invalid-email", isActive: false };
try {
  processUser(invalidUser); // Esto lanzará un error
} catch (error: any) {
  console.error("Error al procesar usuario (inválido):", error.message);
  // Salida: Error al procesar usuario (inválido): Invalid email format for user 2
}

Procesamiento de Colecciones

La composición es extremadamente útil para construir pipelines de procesamiento de arrays, combinando los métodos funcionales de arrays que vimos en la lección anterior (map, filter, reduce, sort).

// Datos de ejemplo de inventario
interface Product {
  id: number;
  name: string;
  price: number;
  category: string;
  stock: number;
}

const inventory: Product[] = [
  { id: 1, name: "Laptop", price: 1200, category: "electronics", stock: 15 },
  { id: 2, name: "Headphones", price: 80, category: "electronics", stock: 0 },
  { id: 3, name: "Coffee Maker", price: 120, category: "kitchen", stock: 5 },
  { id: 4, name: "Desk Chair", price: 250, category: "furniture", stock: 10 },
  { id: 5, name: "Smartphone", price: 800, category: "electronics", stock: 7 }
];

// Funciones de transformación para el pipeline
const filterInStock = (products: Product[]): Product[] => 
  products.filter(p => p.stock > 0);

const filterByCategory = (category: string) => 
  (products: Product[]): Product[] => 
    products.filter(p => p.category === category);

const applyDiscount = (percentage: number) => 
  (products: Product[]): Product[] => 
    products.map(p => ({
      ...p,
      price: parseFloat((p.price * (1 - percentage / 100)).toFixed(2)) // Redondear a 2 decimales
    }));

const sortByPrice = (products: Product[]): Product[] => 
  [...products].sort((a, b) => a.price - b.price);

// Creamos un pipeline para procesar productos:
// 1. Filtrar solo los productos en stock.
// 2. Filtrar solo los de la categoría "electronics".
// 3. Aplicar un 10% de descuento.
// 4. Ordenar por precio de menor a mayor.
const processElectronicsInventory = pipe(
  filterInStock,
  filterByCategory("electronics"),
  applyDiscount(10),
  sortByPrice
);

// Aplicamos el pipeline al inventario
const processedProducts = processElectronicsInventory(inventory);
console.log("Productos electrónicos procesados:", processedProducts);
/*
  Salida esperada:
  [
    { id: 5, name: 'Smartphone', price: 720, category: 'electronics', stock: 7 },
    { id: 1, name: 'Laptop', price: 1080, category: 'electronics', stock: 15 }
  ]
*/

Composición con Currying

El currying es una técnica de programación funcional que transforma una función con múltiples argumentos en una secuencia de funciones, cada una de las cuales toma un solo argumento. Las funciones currificadas son excelentes para la composición, ya que podemos crear versiones pre-configuradas de funciones que se ajustan perfectamente al pipeline.

// Función currificada para filtrar números mayores que un mínimo
const filterGreaterThan = (min: number) => (numbers: number[]): number[] => 
  numbers.filter(n => n > min);

// Función currificada para multiplicar números por un factor
const multiplyBy = (factor: number) => (numbers: number[]): number[] => 
  numbers.map(n => n * factor);

// Componemos funciones currificadas en un pipeline
const processNumbers = pipe(
  filterGreaterThan(10), // Se aplica filterGreaterThan(10)
  multiplyBy(2)          // Luego se aplica multiplyBy(2)
);

const numbersToProcess = [5, 10, 15, 20, 25];
console.log(`Números originales: ${numbersToProcess}`);
console.log(`Números procesados (currying): ${processNumbers(numbersToProcess)}`); // Salida: [30, 40, 50]

Aquí, filterGreaterThan(10) y multiplyBy(2) devuelven funciones que esperan un array de números, que es exactamente lo que espera el pipe.

Consideraciones y Patrones Avanzados (Moderados)

Manejo Básico de Errores en Pipelines

En aplicaciones reales, las funciones en un pipeline pueden fallar. Es importante tener un mecanismo básico para manejar errores. Podemos modificar nuestra función pipe para envolver la ejecución de cada función en un bloque try-catch.

// Implementación de 'pipe' con manejo básico de errores
function safePipe<T>(...fns: Array<(arg: T) => T>): (value: T) => T {
  return (value) => {
    try {
      return fns.reduce((acc, fn) => fn(acc), value);
    } catch (error) {
      console.error("Error en el pipeline:", error);
      return value; // Devolvemos el valor original o un valor por defecto en caso de error
    }
  };
}

// Ejemplo de uso con una función que puede lanzar un error
const parseJSON = (text: string): any => {
  console.log(`Intentando parsear: "${text}"`);
  return JSON.parse(text);
};
const getFirstItem = (array: any[]): any => array[0];

const safeGetFirstItem = safePipe(
  parseJSON,
  getFirstItem
);

console.log(`\n--- Manejo de Errores ---`);
console.log(`Resultado válido: ${safeGetFirstItem('[1,2,3]')}`); // Salida: Intentando parsear: "[1,2,3]" \n Resultado válido: 1
console.log(`Resultado con error: ${safeGetFirstItem('invalid json')}`); // Salida: Error en el pipeline: SyntaxError: Unexpected token 'i'... \n Resultado con error: invalid json

Este safePipe es útil para pipelines donde un error en una etapa no debe detener todo el flujo, sino que permite una recuperación básica o el retorno del valor de entrada.

Comparación: Composición Funcional vs. Encadenamiento de Métodos (OOP)

Es importante distinguir la composición funcional del encadenamiento de métodos que a menudo vemos en la programación orientada a objetos (POO) (como array.map().filter().sort()).

Fundamentos de cada enfoque:

  • Composición Funcional: Se centra en combinar funciones puras e independientes para crear una nueva función. Los datos fluyen a través de las funciones. El estado (si existe) se pasa explícitamente como argumento.
  • Encadenamiento de Métodos (OOP): Se basa en objetos que tienen métodos que, al ser llamados, devuelven el propio objeto (this) o una nueva instancia del objeto, permitiendo encadenar llamadas. Los métodos operan sobre el estado interno del objeto.

Diferencias Clave:

  • Inmutabilidad vs. Estado Mutable: La composición funcional (con funciones puras) promueve la inmutabilidad; cada función produce un nuevo valor y el estado original no se modifica. El encadenamiento de métodos en OOP puede implicar la mutación del estado interno del objeto en cada paso (aunque muchas API modernas como los métodos de array de JS devuelven nuevas instancias).
  • Flexibilidad y Reusabilidad: Las funciones en la composición son piezas de lógica desacopladas que pueden combinarse de infinitas maneras. Los métodos encadenados suelen estar acoplados a la clase o interfaz del objeto.
  • Legibilidad: La composición (especialmente con pipe) puede mejorar la legibilidad al representar el flujo de datos. El encadenamiento de métodos es legible cuando las operaciones son intrínsecas al objeto.

Casos de Uso Apropiados:

  • Composición Funcional: Ideal para construir flujos de procesamiento de datos complejos e independientes del estado. Excelente para la transformación de datos.
  • Encadenamiento de Métodos: Adecuado cuando las operaciones están fuertemente ligadas al estado y comportamiento de un objeto específico, y cuando la secuencia de operaciones es inherente a las capacidades del objeto. (Ejemplo: jQuery.select().addClass().hide()).

Patrones Híbridos: En la práctica, es común combinar ambos enfoques. Por ejemplo, los métodos funcionales de arrays (map, filter, reduce) se encadenan en sí mismos, pero también pueden ser usados como los "bloques de construcción" que se pasan a una función pipe o compose, creando así un pipeline de procesamiento de colecciones como vimos en el ejemplo anterior.

Rendimiento (Consejos)

Aunque la composición funcional hace que el código sea más legible y mantenible, un encadenamiento excesivo de muchas funciones muy pequeñas podría, en teoría, tener una ligera sobrecarga en comparación con un único bucle imperativo optimizado. Sin embargo, en la mayoría de las aplicaciones modernas y con los motores de JavaScript optimizados, esta diferencia es insignificante y el beneficio en la claridad del código supera con creces cualquier coste de rendimiento mínimo. La clave es la claridad y la mantenibilidad.

Conclusión:

La composición de funciones es una herramienta fundamental en la programación funcional que nos permite crear sistemas complejos a partir de componentes simples y reutilizables. Al dominar pipe y compose, y entender cómo se integran con otros conceptos como el currying y los métodos de array, podemos escribir código más modular, legible y robusto en TypeScript.

Aprende TypeScript online

Otros ejercicios de programación de TypeScript

Evalúa tus conocimientos de esta lección Composición de funciones con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Funciones

TypeScript
Test

Reto composición de funciones

TypeScript
Código

Reto tipos especiales

TypeScript
Código

Reto tipos genéricos

TypeScript
Código

Módulos

TypeScript
Test

Polimorfismo

TypeScript
Código

Funciones TypeScript

TypeScript
Código

Interfaces

TypeScript
Puzzle

Funciones puras

TypeScript
Puzzle

Reto namespaces

TypeScript
Código

Funciones flecha

TypeScript
Puzzle

Polimorfismo

TypeScript
Test

Operadores

TypeScript
Test

Conversor de unidades

TypeScript
Proyecto

Funciones flecha

TypeScript
Test

Control de flujo

TypeScript
Código

Herencia

TypeScript
Puzzle

Clases

TypeScript
Puzzle

Proyecto validación de tipado

TypeScript
Proyecto

Clases y objetos

TypeScript
Código

Encapsulación

TypeScript
Test

Herencia

TypeScript
Test

Proyecto sistema de votación

TypeScript
Proyecto

Reto genéricos con clases

TypeScript
Código

Inmutabilidad

TypeScript
Puzzle

Interfaces

TypeScript
Test

Funciones de alto orden

TypeScript
Test

Reto map y filter

TypeScript
Código

Control de flujo

TypeScript
Test

Interfaces

TypeScript
Código

Reto funciones orden superior

TypeScript
Código

Herencia y clases abstractas

TypeScript
Código

Reto tipos mapped

TypeScript
Código

Herencia de clases

TypeScript
Código

Reto funciones puras

TypeScript
Código

Variables y constantes

TypeScript
Puzzle

Introducción a TypeScript

TypeScript
Test

Reto testing unitario

TypeScript
Código

Funciones de primera clase

TypeScript
Puzzle

Clases

TypeScript
Test

OOP y CRUD en TypeScript

TypeScript
Proyecto

Interfaces y su implementación

TypeScript
Código

Tipos genéricos

TypeScript
Test

Namespaces

TypeScript
Test

Operadores y expresiones

TypeScript
Código

Proyecto generador de contraseñas

TypeScript
Proyecto

Reto unión e intersección

TypeScript
Código

Encapsulación

TypeScript
Puzzle

Tipos de unión e intersección

TypeScript
Test

Tipos de unión e intersección

TypeScript
Puzzle

Reto hola mundo en TS

TypeScript
Código

Variables y constantes

TypeScript
Código

Funciones puras

TypeScript
Test

Control de flujo

TypeScript
Código

Introducción a TypeScript

TypeScript
Código

Resolución de módulos

TypeScript
Test

Control de flujo

TypeScript
Puzzle

Reto tipos de utilidad

TypeScript
Código

Reto tipos literales y condicionales

TypeScript
Código

Reto exportar e importar

TypeScript
Código

Propiedades y métodos

TypeScript
Código

Tipos de utilidad

TypeScript
Test

Clases y objetos

TypeScript
Código

Tipos de datos, variables y constantes

TypeScript
Código

Proyecto Minigestor de tareas

TypeScript
Proyecto

Operadores

TypeScript
Puzzle

Funciones flecha y contexto

TypeScript
Código

Proyecto Inventario de productos

TypeScript
Proyecto

Funciones

TypeScript
Puzzle

Reto type aliases

TypeScript
Código

Funciones de alto orden

TypeScript
Puzzle

Funciones y parámetros tipados

TypeScript
Código

Tipos literales

TypeScript
Puzzle

Reto enums

TypeScript
Código

Tipos de utilidad

TypeScript
Puzzle

Modificadores de acceso y encapsulación

TypeScript
Código

Polimorfismo

TypeScript
Puzzle

Tipos genéricos

TypeScript
Puzzle

Reto módulos

TypeScript
Código

Tipos literales

TypeScript
Test

Inmutabilidad

TypeScript
Test

Proyecto Generator de datos

TypeScript
Proyecto

Variables y constantes

TypeScript
Test

Funciones de primera clase

TypeScript
Test

Todas las lecciones de TypeScript

Accede a todas las lecciones de TypeScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Typescript

TypeScript

Introducción Y Entorno

Instalación Y Configuración De Typescript

TypeScript

Introducción Y Entorno

Tipos De Datos, Variables Y Constantes

TypeScript

Sintaxis

Operadores Y Expresiones

TypeScript

Sintaxis

Control De Flujo

TypeScript

Sintaxis

Funciones Y Parámetros Tipados

TypeScript

Sintaxis

Funciones Flecha Y Contexto

TypeScript

Sintaxis

Enums

TypeScript

Sintaxis

Type Aliases Y Aserciones De Tipo

TypeScript

Sintaxis

Clases Y Objetos

TypeScript

Programación Orientada A Objetos

Interfaces Y Su Implementación

TypeScript

Programación Orientada A Objetos

Modificadores De Acceso Y Encapsulación

TypeScript

Programación Orientada A Objetos

Herencia Y Clases Abstractas

TypeScript

Programación Orientada A Objetos

Polimorfismo

TypeScript

Programación Orientada A Objetos

Decoradores Básicos

TypeScript

Programación Orientada A Objetos

Propiedades Y Métodos

TypeScript

Programación Orientada A Objetos

Inmutabilidad

TypeScript

Programación Funcional

Funciones Puras Y Efectos Secundarios

TypeScript

Programación Funcional

Funciones De Primera Clase

TypeScript

Programación Funcional

Funciones De Alto Orden

TypeScript

Programación Funcional

Conceptos Básicos E Inmutabilidad

TypeScript

Programación Funcional

Funciones De Primera Clase Y Orden Superior

TypeScript

Programación Funcional

Composición De Funciones

TypeScript

Programación Funcional

Métodos Funcionales De Arrays (Map, Filter, Reduce)

TypeScript

Programación Funcional

Tipos Literales Y Tipos Condicionales

TypeScript

Tipos Intermedios Y Avanzados

Tipos Genéricos Básicos

TypeScript

Tipos Intermedios Y Avanzados

Tipos De Unión E Intersección

TypeScript

Tipos Intermedios Y Avanzados

Tipos De Utilidad (Partial, Required, Pick, Etc)

TypeScript

Tipos Intermedios Y Avanzados

Unknown, Never Y Tipos Especiales

TypeScript

Tipos Intermedios Y Avanzados

Tipos Mapped

TypeScript

Tipos Intermedios Y Avanzados

Genéricos Con Clases E Interfaces

TypeScript

Tipos Intermedios Y Avanzados

Módulos

TypeScript

Namespaces Y Módulos

Namespaces

TypeScript

Namespaces Y Módulos

Resolución De Módulos

TypeScript

Namespaces Y Módulos

Exportación E Importación De Módulos

TypeScript

Namespaces Y Módulos

Introducción A Módulos

TypeScript

Namespaces Y Módulos

Testing Unitario En Typescript

TypeScript

Testing

Accede GRATIS a TypeScript y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender el concepto fundamental de composición funcional y su origen en las matemáticas, donde una función se aplica al resultado de otra.
  • Implementar funciones de composición básicas como pipe y compose para crear transformaciones de datos encadenadas.
  • Desarrollar pipelines de procesamiento de datos modulares, legibles y mantenibles usando técnicas de composición.
  • Comparar la composición funcional con el encadenamiento de métodos, entendiendo cuándo usar cada enfoque.
  • Aplicar la composición en casos prácticos como la transformación de datos, el procesamiento de colecciones y el manejo básico de errores.