Avancé20 min de lecture

Chaînage Optionnel & Coalescence Nulle

Accède en toute sécurité aux propriétés profondément imbriquées avec le chaînage optionnel (?.) et fournis des valeurs par défaut avec la coalescence nulle (??).

Le Problème

Accéder à des propriétés imbriquées sur null ou undefined génère une TypeError — l'une des erreurs les plus courantes en JavaScript.

javascript
const user = { name: 'Alice' };
console.log(user.address.city);
// TypeError: Cannot read properties of undefined (reading 'city')

Solution traditionnelle — vérifier chaque niveau :

javascript
if (user && user.address && user.address.city) {
  console.log(user.address.city);
}

// Ou avec un ternaire
const city = user && user.address ? user.address.city : 'Unknown';

C'est verbeux et ça empire avec une imbrication plus profonde :

javascript
if (user && user.company && user.company.address && user.company.address.zip) {
  // enfin sûr d'utiliser user.company.address.zip
}

JavaScript moderne fournit deux opérateurs élégants pour résoudre ce problème : le chaînage optionnel (?.) et la coalescence nulle (??).

Chaînage Optionnel (?.)

L'opérateur de chaînage optionnel (?.) retourne undefined au lieu de générer une erreur lors de l'accès à une propriété sur null ou undefined.

Accès aux propriétés :

javascript
const user = { name: 'Alice' };

console.log(user.address?.city);       // undefined (pas d'erreur !)
console.log(user.address?.city?.length); // undefined

Notation entre crochets :

javascript
const key = 'city';
console.log(user.address?.[key]); // undefined

Appels de méthode :

javascript
const user = { name: 'Alice' };
console.log(user.greet?.());    // undefined (pas d'erreur même si greet n'existe pas)

const admin = {
  name: 'Bob',
  greet() { return `Hi, I'm ${this.name}`; }
};
console.log(admin.greet?.());   // "Hi, I'm Bob"

Comportement de court-circuit : Quand le côté gauche est null ou undefined, toute la chaîne s'arrête et retourne undefined. Rien à droite n'est évalué :

javascript
const user = null;
console.log(user?.address?.city); // undefined (pas d'erreur)
// user est null, donc .address n'est jamais accédé

Note : Le chaînage optionnel ne vérifie que null et undefined, pas les autres valeurs falsy comme 0, '', ou false.

Coalescence Nulle (??)

L'opérateur de coalescence nulle (??) fournit une valeur par défaut quand le côté gauche est null ou undefined.

javascript
const name = null ?? 'Anonymous';
console.log(name); // 'Anonymous'

const score = undefined ?? 0;
console.log(score); // 0

Différence clé avec || :

L'opérateur || retourne le côté droit pour toute valeur falsy (null, undefined, 0, '', false, NaN). L'opérateur ?? ne se déclenche que sur null et undefined :

javascript
// || traite 0, '', false comme "manquants"
0 || 42;       // 42 (0 est falsy)
'' || 'hello'; // 'hello' ('' est falsy)
false || true; // true (false est falsy)

// ?? traite seulement null/undefined comme "manquants"
0 ?? 42;       // 0 (0 n'est PAS null/undefined)
'' ?? 'hello'; // '' ('' n'est PAS null/undefined)
false ?? true; // false (false n'est PAS null/undefined)

Combiner avec le chaînage optionnel :

javascript
const city = user?.address?.city ?? 'Unknown';
// Si user, address, ou city est manquant → 'Unknown'

Opérateurs d'affectation logique (ES2021) :

javascript
let a = null;
a ??= 'default';  // a vaut maintenant 'default' (était null)

let b = 0;
b ??= 42;          // b vaut toujours 0 (0 n'est pas null/undefined)

let c = '';
c ||= 'fallback';  // c vaut 'fallback' ('' est falsy)

let d = 5;
d &&= d * 2;       // d vaut 10 (5 est truthy)

Exemples Pratiques

Le chaînage optionnel et la coalescence nulle brillent dans des scénarios réels.

Réponses API avec champs optionnels :

javascript
// L'API peut retourner des données partielles
const response = await fetchUser(id);

const avatar = response?.data?.user?.avatar ?? '/default-avatar.png';
const bio = response?.data?.user?.bio ?? 'No bio provided';

Objets de configuration avec valeurs par défaut :

javascript
function createApp(config) {
  const port = config?.server?.port ?? 3000;
  const host = config?.server?.host ?? 'localhost';
  const debug = config?.debug ?? false;

  console.log(`Starting on ${host}:${port}`);
}

createApp({ server: { port: 8080 } });
// Starting on localhost:8080

createApp(undefined);
// Starting on localhost:3000

Chaînes d'éléments DOM :

javascript
// Accéder en toute sécurité aux éléments DOM imbriqués
const text = document.querySelector('.card')?.querySelector('.title')?.textContent ?? '';

Chaîner plusieurs opérateurs ?. :

javascript
const users = [
  { name: 'Alice', address: { city: 'Paris' } },
  { name: 'Bob' }, // pas d'adresse
  null,            // entrée null
];

const cities = users.map(u => u?.address?.city ?? 'Unknown');
console.log(cities); // ['Paris', 'Unknown', 'Unknown']

Chaînage Optionnel & Coalescence Nulle en Action

html
<div id="output"></div>

<script>
  // Avant : vérifications null verbeuses
  const user1 = { name: 'Alice', address: { city: 'Paris' } };
  const user2 = { name: 'Bob' };
  const user3 = null;

  // Après : chaînage optionnel propre + valeurs par défaut
  const city1 = user1?.address?.city ?? 'Unknown';
  const city2 = user2?.address?.city ?? 'Unknown';
  const city3 = user3?.address?.city ?? 'Unknown';

  // ?? vs || avec des valeurs falsy
  const score = 0;
  const withOr = score || 'no score';   // 'no score' (faux !)
  const withQQ = score ?? 'no score';   // 0 (correct !)

  // Appel de méthode optionnel
  const greet = user1?.sayHello?.() ?? 'No greeting method';

  const output = document.getElementById('output');
  output.innerHTML = `
    <p>City 1: ${city1}</p>
    <p>City 2: ${city2}</p>
    <p>City 3: ${city3}</p>
    <p>score || default: ${withOr}</p>
    <p>score ?? default: ${withQQ}</p>
    <p>Optional method: ${greet}</p>
  `;
</script>

Que retourne `0 ?? 42` ?

Prêt à pratiquer ?

Crée ton compte gratuit pour accéder à l'éditeur de code interactif, lancer les défis et suivre ta progression.