nullish coalescing (??) în TypeScript

a ?? b dă a, iar dacă a este null sau undefined dă b; spre deosebire de ||, păstrează 0, "" și false.

Sintaxă
a ?? b        // b doar dacă a este null sau undefined
x ??= valoare  // atribuie doar dacă x este null sau undefined

Ce face nullish coalescing (??)

Operatorul ?? (din JavaScript ES2020) dă o valoare implicită doar când valoarea din stânga lipsește, adică este null sau undefined. Operatorul vechi || înlocuiește orice valoare falsă, inclusiv 0, "" și false, ceea ce este de obicei greșit pentru numere și texte.

TypeScript elimină null și undefined din tipul rezultatului: dacă a este number | undefined, a ?? 0 este number. Atribuirea x ??= valoare pune valoarea doar dacă x lipsește; este utilă pentru inițializare leneșă și cache.

Nu poți combina ?? cu || sau && fără paranteze; JavaScript dă eroare de sintaxă. Scrie (a || b) ?? c.

Exemple

Exemplul 1: ?? față de ||

Nota 0 și textul gol sunt valori reale. || le înlocuiește greșit, ?? le păstrează.

interface Setari {
    volum?: number;
    prefix?: string;
    notificari?: boolean;
}
const s: Setari = { volum: 0, prefix: "", notificari: false };

console.log("cu ||:", s.volum || 50, JSON.stringify(s.prefix || "Elev:"), s.notificari || true);
console.log("cu ??:", s.volum ?? 50, JSON.stringify(s.prefix ?? "Elev:"), s.notificari ?? true);

const gol: Setari = {};
console.log("lipsă:", gol.volum ?? 50, gol.prefix ?? "Elev:", gol.notificari ?? true);

Rezultat

cu ||: 50 "Elev:" true
cu ??: 0 "" false
lipsă: 50 Elev: true

Exemplul 2: ??= pentru cache

Calculul se face doar prima dată pentru fiecare oraș.

const cache: Record<string, number> = {};
let calcule = 0;

function distanta(oras: string): number {
    cache[oras] ??= (() => {
        calcule++;
        return oras.length * 37;     // calcul „scump”, simulat
    })();
    return cache[oras];
}

console.log(distanta("Iași"), distanta("Timișoara"), distanta("Iași"));
console.log("calcule făcute:", calcule);

Rezultat

148 333 148
calcule făcute: 2

Exemplul 3: Tipul rezultatului nu mai conține undefined

function nota(note: Map<string, number>, elev: string): number {
    return note.get(elev) ?? 1;     // number | undefined devine number
}

const note = new Map([["Ana", 10], ["Mihai", 0]]);
console.log(nota(note, "Ana"), nota(note, "Mihai"), nota(note, "Ioana"));

Rezultat

10 0 1

Greșeli frecvente

  • Scrii a || b ?? c fără paranteze. Este eroare de sintaxă; pune paranteze.
  • Folosești ?? pentru a înlocui și NaN sau "". ?? tratează doar null și undefined.

Comenzi înrudite

  • optional chaining (?.): a?.b citește proprietatea doar dacă a nu este null sau undefined; altfel întreaga expresie dă undefined.
  • null și undefined: Cu strictNullChecks, null și undefined sunt tipuri separate: o variabilă le acceptă doar dacă tipul ei le include.
  • non-null (!): Semnul ! după o expresie îi spune compilatorului că valoarea nu este null sau undefined, fără verificare.
  • parametri opționali și impliciți: Un parametru cu ? poate lipsi la apel (devine undefined); unul cu = valoare primește valoarea implicită.