Historia de la pregunta:
El operador in fue heredado de JavaScript y se utiliza ampliamente para verificar la existencia de una propiedad en un objeto. En TypeScript, su semántica adquiere un significado adicional debido al sistema de tipos: no solo es importante la existencia de un valor, sino también su declaración a nivel de tipo, especialmente en casos de propiedades opcionales.
Problema:
A menudo, los desarrolladores en TypeScript confunden la verificación simple de undefined con la verificación de la existencia real de una propiedad en un objeto. Puede ocurrir un error si la propiedad existe pero su valor es undefined, o si es heredada y no está definida directamente en el objeto.
Solución:
El operador in verifica si la propiedad realmente está presente en la cadena de prototipos del objeto, sin importar su valor. Esto juega un papel importante al comprobar propiedades opcionales o calculadas, lo que ayuda a evitar el tratamiento inesperado de valores falsy:
Ejemplo de código:
interface User { id: number; name?: string; } const user1: User = { id: 1 }; const user2: User = { id: 2, name: undefined }; console.log('name' in user1); // false console.log('name' in user2); // true
Características clave:
in determina la existencia de una propiedad en el objeto o su prototipo, no solo la existencia de un valor¿Cuál es la diferencia entre realizar una verificación de undefined (obj.prop !== undefined) y utilizar in?
La verificación de undefined solo determina el valor, pero no la existencia de la propiedad. Si la propiedad existe, pero es undefined, el resultado será true. Si no hay propiedad en absoluto, su valor también será undefined, pero semánticamente son casos diferentes.
Ejemplo:
const obj: any = { foo: undefined }; console.log('foo' in obj); // true console.log(obj.foo !== undefined); // false console.log('bar' in obj); // false console.log(obj.bar !== undefined); // false
¿Puede el operador in verificar la existencia de una propiedad solo en el propio objeto, ignorando la cadena de prototipos?
No, el estándar in verifica también los prototipos. Para verificar solo los propios, utilice el método hasOwnProperty:
const obj = Object.create({ foo: 123 }); obj.bar = 456; console.log('foo' in obj); // true console.log(obj.hasOwnProperty('foo')); // false
¿Se puede utilizar el operador in para realizar un type narrowing en tipos union en TypeScript?
Sí, en TypeScript in se asemeja a Discriminated Union y permite restringir el tipo a una variante específica:
type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; size: number }; function getArea(shape: Shape) { if ('radius' in shape) { // Aquí shape es un círculo return Math.PI * shape.radius ** 2; } // Aquí shape es un cuadrado return shape.size ** 2; }
inin para matrices (en matrices devuelve true para índices numéricos y propiedades heredadas)in para valores que no son objetos (por ejemplo, null o undefined)En un proyecto con un arreglo de usuarios, se verificó un campo opcional usando user.name !== undefined, lo que resultó en una lógica incorrecta para los usuarios cuyo atributo se había definido explícitamente como undefined.
Ventajas:
Desventajas:
Se utilizó in para verificar con precisión la existencia de un campo opcional de usuario independientemente de su valor, lo que permitió distinguir correctamente entre "no hay campo" y "el campo existe, pero el valor no está dado".
Ventajas:
Desventajas:
in, lo que no siempre es obvio para los principiantes