Quiz : Délices de la déstructuration
Êtes‑vous un maestro du destructuring ?
Ou bien votre Symphonie de la Destruction ?
Ce quiz évaluera votre maîtrise du destructuring en JavaScript : des syntaxes d’objet « basique » au destructuring imbriqué et aux valeurs par défaut. Bonus : questions sur TypeScript et les types inline !
Plongez directement dans l’échauffement – prouvez vos compétences en destructuring ! 👇
Que affichera ce code ?
const person = { name: 'Dan Levy', location: 'Cape Town',};const { name, age } = person;console.log(`Name: ${name}, Age: ${age}`);La propriété age n’existe pas sur person, donc age sera undefined. Ce n’est certainement pas Infinity 😅
Cela donne :
Name: Dan Levy, Age: undefinedQue fera ce code ?
const person = [ 'Dan Levy', 'Cape Town' ];const [ name, origin, age ] = person;console.log(`Name: ${name}, Age: ${age}`);La variable age n’est pas présente dans le tableau tuple, donc elle sera undefined.
Cela donne :
Name: Dan Levy, Age: undefinedEt si on faisait de la destructuration imbriquée ?
'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 propriété birth: { place } n’existe pas sur person, donc elle lèvera une erreur.
Une solution consiste à fournir des valeurs par défaut pour les propriétés imbriquées.
Lors de l’accès aux propriétés imbriquées, soyez prudent, car les erreurs peuvent être difficiles à repérer. De plus, les messages d’erreur varient selon les navigateurs et les plateformes, ce qui complique le débogage.
Dans Chrome moderne : TypeError: Cannot read properties of undefined (reading 'place')
Dans Node, c’est aussi un TypeError parce que JavaScript tente de destructurer place depuis undefined avant même que place ne soit lu.
La formulation exacte varie selon les navigateurs et les environnements d’exécution.
Avec quelques valeurs par défaut, que va‑t‑il faire ?
'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 propriété birth n’existe pas sur person, donc l’ensemble de l’objet a encore besoin d’une valeur par défaut, pas seulement la propriété imbriquée. En gros, il manque un = {} par défaut là‑dedans.
La façon dont c’est écrit indique « si person.birth est undefined, alors place vaut Unknown ». Mais person.birth est undefined, donc il essaie de déstructurer undefined, ce qui provoque une erreur.
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.Que fera ce code ?
const person = { name: { first: 'Dan' }, address: { city: 'Denver' },};const { name: { first = 'Unknown' }, birth: { place = 'Unknown' } = {},} = person;
console.log( `Hi ${first} from ${place}`,);La propriété birth n’existe pas sur person, donc elle retombe sur un objet vide = {}. Cela permet d’utiliser la valeur par défaut.
Maintenant, en tant que paramètres de fonction, que fera-t-elle ?
'use strict';function displayUser({ name = "Unknown", age = -1,} = { place: "Unknown" }) { console.log(`Hi ${name} from ${place}`);}displayUser({ name: "Dan" });Cette fonction extrait les propriétés name et age, en utilisant des valeurs par défaut si nécessaire. Dans ce cas, la clé place de l’objet par défaut n’est qu’un bruit, elle n’est pas utilisée dans displayUser().
Le mode strict ne change rien ici : lire la liaison non déclarée place lève une ReferenceError.
Comment les valeurs undefined sont‑elles gérées ?
'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 fonction displayPlace n’utilisera UN OBJET par défaut que si aucun objet n’est fourni. Ainsi, le seul moyen d’obtenir la valeur par défaut { place: "Unknown" } est d’appeler la fonction sans argument : displayPlace().
Un autre comportement notable est que passer undefined pour place déclenchera l’utilisation de la valeur par défaut, un peu comme le comportement de JSON.stringify (ignore undefined, reconnaît null).
Cela donne :
displayPlace() // UnknowndisplayPlace({ name: "Dan" }) // N/AdisplayPlace({ name: "Dan", place: undefined }) // N/ASemblable au précédent… comment null est‑il géré ?
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 });Dans ce cas, la propriété place est définie sur null lors du premier appel, et sur undefined lors du second. La valeur par défaut pour place n’est utilisée que si l’ensemble de l’objet est absent ou undefined. Les null passeront tels quels, c’est‑à‑dire null.
Maintenant en TypeScript… que fera-t-il ?
'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 signale une erreur parce que place est typé comme string, mais l’appel passe null. L’appel omet également la propriété requise age.
Si vous ignorez les erreurs de type, l’exécution du code affichera null dans la console.
Essayons un peu de renommage/assignation…
'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' });Cela affichera Denver dans la console. La propriété place est renommée en location dans la signature de la fonction. C’est un schéma courant (renommer des propriétés lors de la destructuration) lorsqu’on adapte des structures de données tierces.
Repérez l’erreur de type :
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'} });L’erreur se trouve dans la signature de la fonction greet. Les propriétés age et birth sont absentes dans l’objet passé, elles doivent donc être optionnelles dans la définition du type.
Même si la propriété birth est destructurée avec une valeur par défaut, la définition du type exige qu’elle soit présente. Pour marquer une propriété comme optionnelle en TypeScript, il faut utiliser l’opérateur ?.
Notez que birth?: { place?: string } n’est pas équivalent à birth: { place?: string } | undefined.
Maintenant avec affectation (notez les variables f, l et 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'},});Une autre erreur ! Vous commencez à deviner, n’est-ce pas ?!
Il est difficile de lire les couches de destructuration, avec des valeurs par défaut, l’affectation et les types !
Dès que place est réassigné à la variable p, il n’est plus défini dans la portée de l’instruction console.log.
console.log(`Hi ${f} ${l} from ${place}`); // ❌// to:console.log(`Hi ${f} ${l} from ${p}`); // ✅