es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Por qué no limita “typeof” un tipo de unión cuando el tipo de una propiedad es un discriminante?

Si los miembros de un tipo de unión comparten una propiedad, y el tipo de esa propiedad se puede utilizar para discriminar entre esos miembros, debería poder reducir el tipo dentro de una cláusula if utilizando typeof como condición. Pero no funciona.

Por ejemplo, dentro de la cláusula if a continuación, el tipo de event debería inferirse como UserTextEvent y el tipo de event.target debería inferirse como HTMLInputElement:

type UserTextEvent = { value: string, target: HTMLInputElement };
type UserMouseEvent = { value: [number, number], target: HTMLElement };

type UserEvent = UserTextEvent | UserMouseEvent

function handle(event: UserEvent) {
  if (typeof event.value === 'string') {
    event.value  // string, como se espera

event.target // debería reducirse a HTMLInputElement, pero
             // aún es HTMLInputElement | HTMLElement. ¿Por qué?

}
}
Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    La razón por la cual el tipo de event.target no se restringe solo a HTMLInputElement dentro de la cláusula if es porque el compilador de TypeScript no realiza un análisis profundo de las propiedades para las uniones discriminadas. En otras palabras, solo se fija en la propiedad discriminante (value en este caso) para restringir el tipo de la unión. No examina las propiedades anidadas de los miembros de la unión para hacer inferencias adicionales.

    Para solucionar esta limitación, puedes utilizar una función de tipo guardia para restringir explícitamente el tipo de event.target basado en el tipo de event.value. Aquí tienes un ejemplo de implementación:

    function isUserTextEvent(event: UserEvent): event is UserTextEvent {
      return typeof event.value === 'string';
    }
    
    function handle(event: UserEvent) {
      if (isUserTextEvent(event)) {
        event.value  // string, como se esperaba
    
        event.target // restringido a HTMLInputElement, como se esperaba
      }
    }
    

    Al utilizar la función de tipo guardia isUserTextEvent(), el compilador de TypeScript sabe que event es definitivamente un UserTextEvent dentro de la cláusula if. Por lo tanto, el tipo de event.target se puede inferir como HTMLInputElement en lugar de HTMLInputElement | HTMLElement. Esta técnica se puede utilizar para cualquier unión discriminada donde el tipo de la propiedad discriminante por sí sola no es suficiente para restringir los tipos de las propiedades anidadas.

Comments are closed.