ProgramaciónDesarrollador Frontend

¿Cómo funciona el mecanismo de tipificación de tipos de unión (union types) en TypeScript? ¿Para qué sirve, cómo funciona la reducción de tipo y cuáles son los matices del trabajo con tipos de unión?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Historia del asunto:

Los tipos de unión aparecieron en TypeScript para describir variables y parámetros que pueden aceptar valores de diferentes tipos. Esta posibilidad amplió significativamente la flexibilidad de la tipificación en comparación con los lenguajes clásicos.

Problema:

En JavaScript, las funciones y variables a menudo son poliformales (por ejemplo, aceptan un número o una cadena), lo que complica la tipificación segura. Sin tipos de unión, era necesario utilizar any o duplicar código. Esto aumentaba el número de errores en producción y dificultaba el trabajo en equipos grandes.

Solución:

Los tipos de unión permiten declarar una variable que puede ser de uno de varios tipos, garantizando operaciones correctas después de la verificación. También se implementó el soporte para la reducción de tipos (type narrowing), lo que ayuda al compilador a "entender" con qué está tratando.

Ejemplo de código:

function formatId(id: number | string): string { if (typeof id === 'string') { return id.toUpperCase(); } return id.toString(); }

Características clave:

  • Permiten especificar explícitamente los tipos posibles de variables y parámetros.
  • Funcionan junto con el mecanismo de reducción de tipos a través de verificaciones (por ejemplo, typeof o in).
  • Complican el trabajo con objetos donde la misma clave puede tener diferentes tipos: se requiere un manejo cuidadoso de la lógica de acceso.

Preguntas capciosas.

¿Se puede escribir una unión de objetos con diferentes propiedades y acceder a cualquier propiedad sin verificación?

No. Los tipos de unión permiten acceder solo a aquellas propiedades y métodos que están presentes en todos los tipos. Para acceder a propiedades específicas, se requiere la reducción de tipo.

Ejemplo de código:

type Fish = { swim: () => void; }; type Bird = { fly: () => void; }; function move(animal: Fish | Bird) { // animal.swim(); // Error sin reducción if ('swim' in animal) { animal.swim(); // OK } }

¿Por qué no todos los métodos están disponibles para el tipo de unión string | number?

TypeScript en la unión solo permite lo que existe en todos los tipos incluidos. Para métodos individuales, primero se debe verificar el tipo real.

¿Qué sucederá si no se verifica el tipo en la unión y se intenta llamar a un método específico?

En tal caso, se producirá un error de compilación, ya que no se garantiza la existencia del método. Solo funciona después de verificar el tipo específico.

Errores comunes y anti-patrón

  • Omitir la verificación de tipo antes de usar (puede causar un error de acceso).
  • Describir tipos de unión demasiado amplios (se pierde la seguridad de tipo).
  • La reducción incorrecta lleva a errores invisibles y cheques no exhaustivos.

Ejemplo de la vida real

Caso negativo

Se dio a la variable el tipo string | number y sin verificación se hizo toUpperCase(). Como resultado, la aplicación falla con datos numéricos.

Ventajas:

  • Código escrito rápidamente.

Desventajas:

  • Errores en tiempo de ejecución.
  • Pérdida de confianza en la tipificación estática de TypeScript.

Caso positivo

Verificamos el tipo antes de trabajar con el método:

if (typeof value === 'string') { return value.toUpperCase(); } else { return value.toString(); }

Ventajas:

  • Seguridad completa en el momento de la compilación.
  • Mejor mantenibilidad del código.

Desventajas:

  • Necesidad de escribir verificaciones adicionales.