Skip to main content

Tipos discriminados en TypeScript

⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.


r8vnhill/

Los tipos discriminados en TypeScript permiten modelar variantes limitadas mediante la combinación de type aliases y uniones. Esto es útil cuando se desea controlar las variantes posibles, pero no ofrece el mismo nivel de restricción que las clases selladas de Kotlin, ya que estas variantes pueden ser extendidas en cualquier parte del código.

src/fp/adt/sum/delivery-state.ts
export type DeliveryState =
| { type: "Pending" }
| { type: "Shipped"; trackingNumber: string };

export function signal(state: DeliveryState): string {
switch (state.type) {
case "Pending":
return "Order is pending";
case "Shipped":
return `Order is shipped with tracking number ${state.trackingNumber}`;
}
}
test/fp/adt/sum/delivery-state.test.ts
const state: DeliveryState = {
type: 'Shipped',
trackingNumber: '1234'
};
expect(signal(state))
.toBe('Order is shipped with tracking number 1234');

Extensión de variantes

Supongamos que unx desarrolladorx, sin consultar el diseño original, decide agregar una nueva variante desde otra parte del código:

export type ExtendedDeliveryState = DeliveryState 
| { type: "Returned"; reason: string };

Problemas Potenciales

  1. Manejo Incompleto de Casos: Si el desarrollador olvida agregar un caso para la nueva variante en la función signal original, esto podría resultar en un error en tiempo de ejecución, ya que el switch no manejará el nuevo estado.
  2. Confusión en la Jerarquía de Tipos: Otros desarrolladores que lean el código original podrían no darse cuenta de que existe una variante adicional en otro archivo, lo que podría llevar a confusión y errores de mantenimiento.
  3. Validación en Tiempo de Compilación: A diferencia de las clases selladas en Kotlin, donde el compilador garantiza que todas las variantes sean conocidas y controladas, los tipos discriminados en TypeScript no imponen estas restricciones, permitiendo que se agreguen variantes en cualquier lugar.

Comparación final

CaracterísticaKotlinTypeScript
Control de JerarquíaLas clases selladas imponen restricciones fuertes, permitiendo la herencia solo dentro del mismo paquete y módulo, garantizando control total sobre las variantes posibles.Los tipos discriminados no imponen las mismas restricciones, permitiendo que cualquier parte del código agregue nuevas variantes. Esto puede llevar a un mantenimiento más difícil y propenso a errores.
Exhaustividad en PatronesEl compilador obliga a manejar todas las variantes en un when, asegurando que ninguna variante se quede sin manejar.En TypeScript, se puede usar switch, pero no es obligatorio manejar todas las variantes, aunque el compilador puede advertir si se omite un caso.
Reflexión y Listado de SubclasesKotlin permite listar todas las subclases de una clase sellada utilizando reflexión, facilitando la validación de estados en tiempo de ejecución.TypeScript no tiene soporte nativo para reflexión, lo que requiere mantener manualmente una lista de variantes, lo que puede ser propenso a errores.
Interoperabilidad y FlexibilidadKotlin ofrece un fuerte control de tipos y coherencia, pero puede ser menos flexible para extender dinámicamente el sistema.TypeScript permite mayor flexibilidad y dinamismo, ideal para aplicaciones que necesitan extensibilidad en tiempo de ejecución, pero a costa de un control más laxo sobre las variantes.
Manejo de ErroresEl uso de clases selladas facilita la detección de errores en tiempo de compilación, ya que todas las variantes son conocidas y controladas.TypeScript puede permitir la introducción de variantes no controladas, lo que podría dar lugar a errores en tiempo de ejecución si no se manejan adecuadamente.

Beneficios y limitaciones

Beneficios

  • Flexibilidad en la adición de variantes: Los tipos discriminados permiten agregar nuevas variantes en cualquier lugar del código, lo que proporciona una mayor flexibilidad al modelar diferentes estados o tipos de datos.
  • Simplicidad en la sintaxis: La combinación de type aliases y uniones en TypeScript hace que la definición de tipos discriminados sea sencilla y fácil de entender, lo que facilita su uso y mantenimiento.
  • Interoperabilidad con JavaScript: Al estar basado en JavaScript, TypeScript permite que los tipos discriminados se integren fácilmente en proyectos existentes, lo que facilita la migración y adaptación de código.
  • Capacidad de inferencia de tipos: TypeScript puede inferir tipos en muchas situaciones, lo que significa que lxs desarrolladorxs pueden beneficiarse de la verificación de tipos sin tener que especificar cada detalle.

Limitaciones

  • Falta de restricciones fuertes: A diferencia de las clases selladas en Kotlin, los tipos discriminados no imponen restricciones fuertes sobre las variantes, lo que puede permitir la introducción de variantes no controladas y complicar el mantenimiento del código.
  • Menor seguridad en tiempo de compilación: La posibilidad de agregar variantes en cualquier parte del código puede dar lugar a errores que no se detectan hasta que se ejecuta el programa, aumentando el riesgo de fallos en tiempo de ejecución.
  • Manejo incompleto de casos: Si lxs desarrolladorxs no manejan todas las variantes en un switch o if, puede dar lugar a comportamientos inesperados o errores que no se detectan hasta que se ejecuta el código.
  • No hay soporte nativo para reflexión: A diferencia de Kotlin, TypeScript carece de un mecanismo de reflexión que permita listar las variantes de un tipo discriminado, lo que puede complicar ciertas tareas de validación o introspección en tiempo de ejecución.

¿Qué aprendimos?

En esta lección, hemos explorado cómo los tipos discriminados en TypeScript nos permiten modelar variantes limitadas mediante la combinación de type aliases y uniones.

Puntos clave

  1. Control de Variantes: Aunque los tipos discriminados son útiles para manejar variantes, no ofrecen el mismo nivel de control que las clases selladas en Kotlin. En TypeScript, cualquier parte del código puede agregar nuevas variantes, lo que puede complicar el mantenimiento y la legibilidad del código.
  2. Manejo de Patrones: Mientras que Kotlin exige que se manejen todas las variantes en un when, TypeScript permite usar switch, pero no obliga a manejar todos los casos. Esto puede llevar a errores en tiempo de ejecución si no se tienen en cuenta todas las variantes posibles.
  3. Falta de Soporte para Reflexión: A diferencia de Kotlin, que permite listar todas las subclases de una clase sellada, TypeScript no tiene soporte nativo para reflexión. Esto puede complicar la validación de variantes en tiempo de ejecución y requiere un manejo manual de las variantes.
  4. Flexibilidad y Simplicidad: La flexibilidad de los tipos discriminados en TypeScript es una ventaja en aplicaciones que requieren una estructura más dinámica. Además, la sintaxis es simple y fácil de entender, lo que facilita su implementación y uso.
  5. Beneficios y Limitaciones: Hemos discutido los beneficios de los tipos discriminados, como su flexibilidad y la capacidad de inferencia de tipos, así como sus limitaciones, incluyendo la falta de restricciones y la menor seguridad en tiempo de compilación.

En resumen, los tipos discriminados son una herramienta poderosa en TypeScript para modelar variantes de datos, pero es esencial ser consciente de sus limitaciones y de cómo pueden afectar el mantenimiento y la seguridad del código. Este entendimiento nos permitirá tomar decisiones informadas sobre cuándo y cómo utilizarlos eficazmente en nuestros proyectos.