Pregunta

La especificación TypeScript establece en §4.15.6 sobre la && operador:

El operador && permite que los operandos sean de cualquier tipo y produce un resultado del mismo tipo que el segundo operando.

En Javascript, el && El operador devuelve el primer operando si es falso; de lo contrario, devuelve el segundo operando (ver ECMA-262 §11.11).

Eso significa que si el operando izquierdo es falso, && devolverá un valor que coincida con el tipo del operando izquierdo.Por ejemplo,

typeof ( false && {}      ) === "boolean" // true
typeof ( ''    && 1       ) === "string"  // true
typeof ( null  && "hello" ) === "object"  // true
typeof ( NaN   && true    ) === "number"  // true

La escritura mecanografiada, de acuerdo con la regla citada anteriormente, incorrectamente predecir que los tipos de las expresiones anteriores serán Object, Number, String y Boolean, respectivamente.

¿Me estoy perdiendo de algo?¿Existe una buena razón para hacer que el tipo de && ¿La expresión coincide con el tipo del segundo operando?¿No debería comportarse el tipo de resultado como el || operador y devolver el mejor tipo común de los dos operandos, y Any si no existe el mejor tipo común?

¿Fue útil?

Solución

En pocas palabras, aquí no existe una solución que satisfaga a todos.

Considere este modismo común:

var customer = GetCustomer(...); // of type 'Customer'
var address = customer && customer.address;
if(address) {
    printAddressLabel(address); // Signature: (Address) => void
} else {
    // Couldn't find the customer or the customer has no address on file
}

Sería bastante tonto darse por vencido y decidir que "dirección" es "cualquiera" porque no existe el mejor tipo común entre Cliente y Dirección.

En la mayoría de los casos en los que se utiliza el operador &&, ya sea los tipos ya coincide, o && se utiliza de manera fusionante de valores como se muestra arriba.En cualquier caso, devolver el tipo del operando correcto le da al usuario el tipo esperado.

Si bien la seguridad de tipos técnicamente está fallando en este punto, no lo hace de una manera que pueda resultar en un error.O vas a probar la veracidad del valor resultante (en cuyo caso el tipo es más o menos irrelevante), o vas a utilizar el operando presunto correcto para alguna operación (el ejemplo anterior hace ambas cosas).

Si miramos los ejemplos que enumeró y pretendemos que el operando izquierdo es indeterminadamente verdadero o falso y luego intentamos escribir un código sensato que funcione con el valor de retorno, se vuelve mucho más claro: simplemente no hay mucho que pueda hacer. hacer con 'false && {}' que aún no esté en una posición de argumento o prueba de veracidad de 'cualquier'.


Apéndice

Dado que a algunas personas no les convenció lo anterior, aquí hay una explicación diferente.

Supongamos por un momento que el sistema de tipos TypeScript agregó tres tipos nuevos: Truthy<T>, Falsy<T>, y Maybe<T>, que representa posibles valores verdaderos/falsos de tipo T.Las reglas para estos tipos son las siguientes:

  1. Truthy<T> se comporta exactamente como T
  2. No puedes acceder a ninguna propiedad de Falsy<T>
  3. Una expresión de tipo. Maybe<T>, cuando se utiliza como condición en un if bloque, se convierte en Truthy<T> en el cuerpo de ese mismo if bloque y un Falsy<T> en el else bloquear

Esto te permitiría hacer cosas como esta:

function fn(x: Maybe<Customer>) {
   if(x) {
      console.log(x.address); // OK
   } else {
      console.log(x.phone); // Error: x is definitely falsy
   }
   console.log(x.name); // Warning: x might be falsy!
}

Bastante bien hasta ahora.Ahora podemos descubrir cuáles son las reglas de tipo para el operador &&.

  • Truthy<T> && x debería haber un error: si se sabe que el lado izquierdo es verdadero, debería haber escrito x
  • Falsy<T> && x debería ser un error: si se sabe que el lado izquierdo es falso, x es un código inalcanzable
  • Maybe<T> && x debería producir...¿qué?

conocemos el resultado de Maybe<T> && x será un valor falso de tipo T, o x.No puede producir Truthy<T> (a menos que T == el tipo de x en cuyo caso toda esta discusión es discutible).Llamemos a este nuevo tipo Falsy<T> XOR Maybe<U>.

¿Cuáles deberían ser las reglas de Falsy<T> XOR Maybe<U> ¿ser?

  • Claramente, no puedes usar propiedades de T en eso.Si el valor es de tipo T, es falso y no es seguro de usar.
  • Deberías poder utilizarlo como Maybe<U>, desde Falsy<T> y Falsy<U> tener los mismos comportamientos
  • No deberías poder usar propiedades de U, porque el valor aún podría ser falso.
  • Si lo usas en un if prueba, entonces debería convertirse en una Truthy<U> en el bloque de ese if declaración

En otras palabras, Falsy<T> XOR Maybe<U> es Maybe<U>.Sigue todas las mismas reglas.No necesitas complicar el sistema de tipos en absoluto agregando este extraño XOR tipo, porque ya existe un tipo que se ajusta a todas las especificaciones que necesita.

Esto es un poco como darle a alguien una caja y decirle: "Esta es una caja de basura vacía o una caja llena de materiales reciclables".Puedes vaciar de forma segura el contenido de la caja en el contenedor de reciclaje.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top