En TypeScript, el emparejamiento de patrones se implementa a través de "uniones discriminadas". A cada objeto en la unión se le asigna un campo-discriminador obligatorio (generalmente una cadena, por ejemplo type), por el cual TypeScript diferencia las variantes.
Ejemplo:
type Success = { type: 'success'; data: string }; type Failure = { type: 'failure'; error: string }; type Result = Success | Failure; function handleResult(result: Result) { switch (result.type) { case 'success': // result: Success console.log(result.data); break; case 'failure': // result: Failure console.error(result.error); break; } }
En el switch/case o if por el campo-discriminador, TypeScript "reducirá" el tipo exactamente a la variante necesaria.
Principales ventajas:
Si se añade una nueva variante a la unión discriminada, ¿demandará TypeScript obligatoriamente actualizar todos los switch-case para manejar la nueva variante?
Respuesta: No, solo si se añade explícitamente el manejo de la variante "imposible". Por ejemplo, utilizando la función never:
Ejemplo:
function assertNever(x: never): never { throw new Error('Variant unexpected: ' + x); } function handle(r: Result) { switch(r.type) { case 'success': /* ... */; break; case 'failure': /* ... */; break; default: return assertNever(r); // TS mostrará un error si aparece un nuevo tipo } }
Historia
Después de extender el tipo "Result" con una nueva variante ('pending'), en varios lugares de la aplicación, los viejos switch-case no manejaron este caso. Como resultado, parte de las interfaces dejaron de funcionar. El error solo fue notado en producción una semana después del lanzamiento.
Historia
Intentar usar una unión discriminada sin un discriminador único (el campo type se duplicaba en dos tipos) llevó a la "dilución" de tipos: TypeScript dejó de restringir el tipo con precisión, y fue posible acceder a campos inexistentes sin un error de compilación. Varios errores críticos se fueron a producción.
Historia
En un proyecto, se implementó el emparejamiento de patrones a través de if-else en varios campos en lugar de utilizar un único discriminador explícito. Esto complicó la transición a la verificación de exhaustividad con la función never y dificultó la legibilidad del código: los switch-case no funcionaban correctamente y las nuevas variantes "rompían" la lógica existente.