ts-pattern en TypeScript: guía completa con ejemplos
La librería ts-pattern aporta a TypeScript un potente y expresivo mecanismo de pattern matching (coincidencia de patrones), inspirado en lenguajes como OCaml, Rust, Haskell y Scala. En lugar de largas cadenas de if-else o switch-case, ts-pattern permite describir la lógica de ramificación de forma declarativa, verificando la estructura y los tipos de datos. Esto es especialmente valioso al trabajar con tipos de datos algebraicos (ADT), como uniones discriminadas (discriminated unions), valores opcionales (Option) o resultados (Result).
¿Por qué es útil? Primero, el código se vuelve más legible y conciso. En lugar de analizar objetos anidados complejos con múltiples comprobaciones, describes la estructura de datos deseada y la librería encuentra la coincidencia adecuada. Segundo, ts-pattern proporciona una verificación de exhaustividad (exhaustiveness check): si no manejas todos los casos posibles, TypeScript mostrará un error en tiempo de compilación. Esto reduce drásticamente los errores relacionados con estados omitidos. Tercero, la librería está completamente tipada y se integra con el sistema de tipos de TypeScript, haciendo que la refactorización sea segura y predecible.
ts-pattern no es solo un reemplazo de switch. Es una herramienta completa para la descomposición de datos que permite comparar no solo valores, sino también sus tipos, estructuras, rangos e incluso predicados personalizados. La librería se usa activamente en proyectos donde la fiabilidad y la expresividad son clave: desde aplicaciones frontend con React/Redux hasta servicios backend con Node.js.
Instalación
La instalación de la librería se realiza a través del gestor de paquetes npm (o yarn/pnpm). Asegúrate de que tu proyecto use TypeScript versión 4.0 o superior.
npm install ts-pattern
Una vez instalada, la librería está lista para usar. No se requiere ninguna configuración adicional en el tsconfig.json.
Inicio rápido
Comencemos con un ejemplo clásico: el manejo del resultado de una petición HTTP. Imaginemos que tenemos una unión discriminada (discriminated union) que describe el estado de carga de datos.
import { match } from 'ts-pattern';
// Definimos los posibles estados
type State =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: string }
| { status: 'error'; error: Error };
// Función que devuelve un texto según el estado
function getStatusMessage(state: State): string {
return match(state)
.with({ status: 'idle' }, () => 'Esperando...')
.with({ status: 'loading' }, () => 'Cargando...')
.with({ status: 'success' }, ({ data }) => `Datos: ${data}`)
.with({ status: 'error' }, ({ error }) => `Error: ${error.message}`)
.exhaustive(); // verificamos que todos los casos están cubiertos
}
// Ejemplos de uso
console.log(getStatusMessage({ status: 'idle' })); // "Esperando..."
console.log(getStatusMessage({ status: 'loading' })); // "Cargando..."
console.log(getStatusMessage({ status: 'success', data: '¡Hola, mundo!' })); // "Datos: ¡Hola, mundo!"
console.log(getStatusMessage({ status: 'error', error: new Error('404') })); // "Error: 404"
Este ejemplo muestra la idea principal: comparamos el objeto state con diferentes patrones. Cada patrón es una descripción parcial de la estructura del objeto. Si la estructura coincide, se ejecuta la función correspondiente. El método .exhaustive() garantiza que no olvidamos manejar ninguna de las variantes.
Métodos y funciones principales
La librería proporciona varias funciones y métodos clave. Veámoslos en detalle.
1. match(value)
Firma: match<I, O>(value: I): Match<I, O>
Qué hace: