Quiz: Delicias dedesestructuración
¿Dominas la desestructuración?
¿O es tu Sinfonía de la Destrucción?
Este quiz evaluará tu dominio del Destructuring en JavaScript: desde la sintaxis “básica” de objetos hasta destructuring anidado y valores por defecto. ¡Además, incluye preguntas extra sobre TypeScript y tipos inline!
¡Vamos al calentamiento y demuestra tus habilidades de Destructuring! 👇
¿Qué imprimirá este código?
const person = { name: 'Dan Levy', location: 'Cape Town',};const { name, age } = person;console.log(`Name: ${name}, Age: ${age}`);La propiedad age no existe en person, así que age será undefined. Definitivamente no es Infinity 😅
Esto resulta en:
Name: Dan Levy, Age: undefined¿Qué hará este código?
const person = [ 'Dan Levy', 'Cape Town' ];const [ name, origin, age ] = person;console.log(`Name: ${name}, Age: ${age}`);La variable age no está presente en el arreglo tuple, así que será undefined.
Esto resulta en:
Name: Dan Levy, Age: undefined¿Qué tal una desestructuración anidada?
'use strict';const person = { name: { first: 'Dan' }, address: { city: 'Denver' },};const { name: { first }, address: { city }, birth: { place },} = person;console.log( `First: ${first}, City: ${place}`,);La propiedad birth: { place } no existe en person, por lo que lanzará un error.
Una solución es proporcionar valores predeterminados para las propiedades anidadas.
Al acceder a propiedades anidadas, ten cuidado, ya que los errores pueden ser difíciles de detectar. Además, los mensajes de error varían entre navegadores y otras plataformas, lo que complica un poco la depuración.
En Chrome moderno: TypeError: Cannot read properties of undefined (reading 'place')
En Node, también es un TypeError porque JavaScript intenta desestructurar place de undefined antes de que place se lea.
La redacción exacta varía entre navegadores y entornos de ejecución.
Ahora con algunos valores predeterminados, ¿qué hará esto?
'use strict';const person = { name: { first: 'Dan' }, address: { city: 'Denver' },};const { name: { first = 'Unknown' }, birth: { place = 'Unknown' },} = person;console.log( `Hi ${first} from ${place}`,);La propiedad birth no existe en person, así que todo el objeto aún necesita un valor predeterminado, no solo la propiedad anidada. Básicamente falta un = {} predeterminado allí.
La forma en que está escrito dice “si person.birth es undefined, entonces place es Unknown”. Pero person.birth es undefined, así que está intentando desestructurar undefined, lo que produce un error.
In modern Chrome: `TypeError: Cannot read properties of undefined (reading 'place')`
In Node, this is also a `TypeError` because JavaScript tries to destructure `place` from `undefined`.
Exact wording varies between browsers and runtimes.¿Qué hará esto?
const person = { name: { first: 'Dan' }, address: { city: 'Denver' },};const { name: { first = 'Unknown' }, birth: { place = 'Unknown' } = {},} = person;
console.log( `Hi ${first} from ${place}`,);La propiedad birth no existe en person, así que recurre a un objeto vacío = {}. Esto permite que se use el valor predeterminado.
Ahora como parámetros de función, ¿qué hará esto?
'use strict';function displayUser({ name = "Unknown", age = -1,} = { place: "Unknown" }) { console.log(`Hi ${name} from ${place}`);}displayUser({ name: "Dan" });Esta función extrae las propiedades name y age, usando valores predeterminados si es necesario. En este caso, la clave place del objeto por defecto es solo ruido, no se usa dentro de displayUser().
El modo estricto no cambia esto: leer la variable no declarada place lanza un ReferenceError.
¿Cómo se manejan los valores undefined?
'use strict';function displayPlace({ name = "N/A", place = "N/A", age = -1,} = { place: "Unknown" }) { console.log(`${place}`);}displayPlace({ name: "Dan" });displayPlace({ name: "Dan", place: undefined });displayPlace({ name: "Dan", place: "Joburg" });La función displayPlace SOLO usará un objeto predeterminado si no se pasa ningún objeto. Así, la única forma de obtener el valor predeterminado { place: "Unknown" } es con cero argumentos displayPlace().
Otro comportamiento notable aquí es que pasar undefined para place hará que se use el valor predeterminado, algo similar al comportamiento de JSON.stringify (ignora undefined, reconoce null).
Esto produce:
displayPlace() // UnknowndisplayPlace({ name: "Dan" }) // N/AdisplayPlace({ name: "Dan", place: undefined }) // N/ASimilar al anterior… ¿cómo se maneja null?_
function displayPlace({ name = "N/A", place = "N/A", age = -1,} = { place: "Unknown" }) { console.log(`${place}`);}displayPlace({ name: "Dan", place: null });displayPlace({ name: "Dan", place: undefined });En este caso, la propiedad place se establece en null en la primera llamada y en undefined en la segunda. El valor predeterminado para place solo se usa si el objeto completo falta o es undefined. Los null pasarán como null.
Ahora en TypeScript… ¿qué hará esto?
'use strict';function displayPlace( { name = 'N/A', place = 'N/A', }: { name: string; place: string; age: number; },) { console.log(`${place}`);}displayPlace({ name: 'Dan', place: null });TypeScript informa un error porque place está tipado como string, pero la llamada pasa null. Además, la llamada omite la propiedad requerida age.
Si ignoras los errores de tipo, ejecutar el código imprimirá null en la consola.
Probemos un poco de renombrado/asignación…
'use strict';function displayPlace({ name = 'N/A', place: location = 'N/A',}: { name: string; place: string; age?: number;}) { console.log(`${location}`);}displayPlace({ name: 'Dan', place: 'Denver' });Esto imprimirá Denver en la consola. La propiedad place se renombra a location en la firma de la función. Es un patrón común (renombrar propiedades durante la desestructuración) al adaptar estructuras de datos de terceros.
Detecta el error de tipo:
function greet({ name: {first = "N/A", last = "N/A"}, birth: {place = "N/A"} = {}, age = -1,}: { name: {first?: string, last?: string}; birth: {place?: string}; age: number;}) { console.log(`Hi ${first} ${last} from ${place}`);}greet({ name: {first: 'Dan'} });El error está en la firma de la función greet. Las propiedades age y birth faltan en el objeto pasado, por lo que deberían ser opcionales en la definición del tipo.
Aunque la propiedad birth se desestructura con un valor predeterminado, la definición del tipo requiere que esté presente. Para marcar una propiedad como opcional en TypeScript, debes usar el operador ?.
Nota que birth?: { place?: string } no es lo mismo que birth: { place?: string } | undefined.
Ahora con asignación (nota las variables f, l y p)
'use strict';function greet( { name: {first: f = "N/A", last: l = "N/A"}, birth: {place: p = "N/A"} = {}, age = -1, }: { name: {first?: string, last?: string}; birth?: {place?: string}; age?: number; }) { console.log(`Hi ${f} ${l} from ${place}`); // What will 👆 do?}greet({ name: {first: 'Dan', last: 'Levy'}, birth: {place: 'Cape Town'},});¡Otro error! ¿Estás empezando a adivinar, ¿no?!
Es difícil leer capas de desestructuración, con valores predeterminados, asignación y tipos!
En cuanto place se reasigna a la variable p, ya no está definido en el alcance de la sentencia console.log.
console.log(`Hi ${f} ${l} from ${place}`); // ❌// to:console.log(`Hi ${f} ${l} from ${p}`); // ✅