Introduzione
JavaScript moderno ha introdotto diversi strumenti per scrivere codice più sicuro, leggibile e conciso. Tra questi, optional chaining e nullish coalescing sono particolarmente utili quando un’applicazione lavora con dati provenienti da API, moduli di configurazione o oggetti complessi.
Quando accediamo a una proprietà annidata, possiamo incontrare valori mancanti. Ad esempio, un server potrebbe restituire un utente senza indirizzo, oppure una risposta potrebbe non contenere sempre tutti i campi previsti. Prima di queste funzionalità, era comune scrivere molte verifiche manuali:
const citta = utente &&
utente.profilo &&
utente.profilo.indirizzo &&
utente.profilo.indirizzo.citta; Questo approccio funziona, ma è verboso e rende il codice difficile da leggere. Con ES2020, parte dell’evoluzione di ES6+, possiamo usare l’operatore optional chaining ?. e l’operatore nullish coalescing ??.
In questo tutorial costruiremo un piccolo esempio che simula la visualizzazione di un profilo utente ricevuto da un servizio remoto.
Codice completo
const rispostaApi = {
id: 42,
nome: "Marta",
profilo: {
ruolo: "Frontend developer"
},
preferenze: {
notifiche: false
}
};
// Optional chaining:
// restituisce undefined se una proprietà intermedia è null o undefined.
const citta = rispostaApi.profilo?.indirizzo?.citta;
// Nullish coalescing:
// usa il valore a destra solo quando quello a sinistra è null o undefined.
const nomeVisualizzato = rispostaApi.nome ?? "Utente anonimo";
const cittaVisualizzata = citta ?? "Città non specificata";
// L´optional chaining può essere usato anche con i metodi.
const iniziali = rispostaApi.nome?.toUpperCase()?.slice(0, 2);
// Accesso sicuro a un metodo potenzialmente inesistente.
const messaggioBenvenuto = rispostaApi.messaggi?.benvenuto?.();
// Attenzione: false è un valore valido e non viene sostituito da ??.
const notificheAttive =
rispostaApi.preferenze?.notifiche ?? true;
console.log("Nome:", nomeVisualizzato);
console.log("Città:", cittaVisualizzata);
console.log("Iniziali:", iniziali);
console.log("Messaggio:", messaggioBenvenuto);
console.log("Notifiche attive:", notificheAttive); Spiegazione
Optional chaining con le proprietà
L’operatore ?. interrompe l’accesso a una catena di proprietà quando incontra null o undefined. In quel caso il risultato dell’espressione è undefined, invece di generare un errore.
const utente = {
nome: "Luca",
contatti: {
email: "[email protected]"
}
};
const email = utente.contatti?.email;
const telefono = utente.contatti?.telefono;
const indirizzo = utente.indirizzo?.via;
console.log(email); // "[email protected]"
console.log(telefono); // undefined
console.log(indirizzo); // undefined Senza optional chaining, l’accesso a utente.indirizzo.via causerebbe un TypeError, perché indirizzo non esiste. L’operatore è quindi molto utile quando la struttura dei dati non è completamente garantita.
Optional chaining con gli array
È possibile usare ?. anche per leggere un elemento di un array. La sintassi ?.[indice] evita errori quando l’array potrebbe mancare.
const ordine = {
prodotti: [
{ nome: "Tastiera", prezzo: 49.90 }
]
};
const primoProdotto = ordine.prodotti?.[0]?.nome;
const prodottoInesistente = ordine.prodotti?.[5]?.nome;
console.log(primoProdotto); // "Tastiera"
console.log(prodottoInesistente); // undefined Optional chaining con le funzioni
La sintassi funzione?.() permette di chiamare una funzione solo se esiste. È utile, per esempio, quando un callback è opzionale.
function eseguiOperazione(valore, callback) {
const risultato = valore * 2;
// Il callback viene invocato solo se è una funzione definita.
callback?.(risultato);
}
eseguiOperazione(5, risultato => {
console.log("Risultato:", risultato);
});
eseguiOperazione(10); // Nessun errore Nullish coalescing
L’operatore ?? restituisce il valore a sinistra se questo non è null e non è undefined. Altrimenti restituisce il valore predefinito a destra.
const titolo = null ?? "Titolo predefinito";
const descrizione = undefined ?? "Nessuna descrizione";
console.log(titolo); // "Titolo predefinito"
console.log(descrizione); // "Nessuna descrizione" La differenza principale rispetto all’operatore OR, ||, riguarda i valori falsy come 0, false e la stringa vuota. Questi valori possono essere perfettamente validi e non devono essere sostituiti automaticamente.
const quantita = 0;
const conOr = quantita || 1;
const conNullish = quantita ?? 1;
console.log(conOr); // 1
console.log(conNullish); // 0
const attivo = false;
console.log(attivo || true); // true
console.log(attivo ?? true); // false Quando si usano entrambi gli operatori nella stessa espressione, è buona pratica inserire parentesi esplicite. JavaScript non permette di mescolare direttamente ?? con || o && senza parentesi.
Best practice
- Usa optional chaining per dati realmente opzionali. Non nascondere errori di progettazione o proprietà che dovrebbero essere sempre presenti.
- Preferisci
??a||quando zero, false o stringa vuota sono valori validi. È una scelta importante nei moduli di configurazione e nei form. - Non abusare dell’optional chaining. Se una proprietà è obbligatoria, un errore esplicito può aiutare a individuare prima un problema.
- Combina gli operatori con nomi descrittivi. Salvare il risultato in una costante come
cittaVisualizzatamigliora la leggibilità. - Controlla la compatibilità dell’ambiente. I browser moderni e le versioni attuali di Node.js supportano queste funzionalità, ma per progetti legacy può essere necessario usare Babel o un sistema di transpiling.
- Non usare
?.per sostituire la validazione dei dati. Quando i dati arrivano da un’API, è comunque consigliabile validarne la forma con controlli dedicati o librerie specifiche.
Riepilogo
L’optional chaining permette di accedere in modo sicuro a proprietà, elementi di array e funzioni potenzialmente mancanti. La sintassi principale è oggetto?.proprieta, mentre per gli array si può usare array?.[indice] e per le funzioni callback?.().
Il nullish coalescing consente invece di definire un valore alternativo solo quando il risultato originale è null o undefined. Questo lo rende più preciso dell’operatore || in molti casi pratici.
Usati insieme, questi strumenti rendono il codice ES6+ più robusto, soprattutto nella gestione di risposte API, configurazioni facoltative e dati annidati. La sintassi più comune è:
const valore = oggetto?.proprieta?.annidata ?? valorePredefinito; 