non-null (!) în TypeScript

Semnul ! după o expresie îi spune compilatorului că valoarea nu este null sau undefined, fără verificare.

Sintaxă
valoare!            // elimină null și undefined din tip
obiect.camp!.metoda()
let x!: number;     // câmp sau variabilă inițializată mai târziu

Ce face non-null (!)

Operatorul ! pus după o expresie elimină null și undefined din tipul ei: dacă gasit are tipul Elev | undefined, gasit! are tipul Elev. Este o aserțiune: nu se verifică nimic la rulare. Dacă valoarea chiar lipsește, primești eroarea Cannot read properties of undefined.

Folosește-l doar când ești sigur, din motive pe care TypeScript nu le vede: elementul există în pagină pentru că l-ai pus tu în HTML, cheia există în Map pentru că ai adăugat-o pe rândul de mai sus. În aproape toate celelalte cazuri, o verificare (if), ?. sau ?? sunt mai sigure.

Forma camp!: Tip la declarare (definite assignment assertion) spune că un câmp de clasă sau o variabilă primește valoare mai târziu, într-un loc pe care tsc nu îl poate urmări. Nu confunda cu !x (negație logică, pus înainte).

Exemple

Exemplul 1: Cheie adăugată chiar înainte

Cheia a fost pusă în Map pe rândul anterior, deci get nu poate da undefined. TypeScript nu știe asta; ! îi spune.

const grupe = new Map<string, string[]>();

function adauga(oras: string, elev: string): void {
    if (!grupe.has(oras)) grupe.set(oras, []);
    grupe.get(oras)!.push(elev);
}

adauga("Iași", "Ana");
adauga("Cluj", "Mihai");
adauga("Iași", "Ioana");
console.log(grupe);

Rezultat

Map(2) { 'Iași' => [ 'Ana', 'Ioana' ], 'Cluj' => [ 'Mihai' ] }

Exemplul 2: Când ! te minte

Elevul căutat nu există; ! a ascuns problema, iar programul aruncă la rulare.

const elevi = [{ nume: "Ana", nota: 10 }];

try {
    const e = elevi.find((x) => x.nume === "Mihai")!;
    console.log(e.nota);
} catch (eroare) {
    console.log("Eroare la rulare:", (eroare as Error).message);
}

const sigur = elevi.find((x) => x.nume === "Mihai");
console.log(sigur?.nota ?? "elevul nu există");

Rezultat

Eroare la rulare: Cannot read properties of undefined (reading 'nota')
elevul nu există

Exemplul 3: Câmp inițializat într-o metodă separată

conexiune! spune că valoarea este dată în porneste(), nu în constructor.

class Serviciu {
    conexiune!: string;

    porneste(): this {
        this.conexiune = "conectat la server-iasi-01";
        return this;
    }
}

console.log(new Serviciu().porneste().conexiune);

Rezultat

conectat la server-iasi-01

Greșeli frecvente

  • Pui ! peste tot unde tsc spune possibly ‘undefined’. Ai mutat erorile de la compilare la rulare.
  • Scrii x! când voiai !x. Primul este aserțiune de tip, al doilea este negație logică.

Comenzi înrudite

  • null și undefined: Cu strictNullChecks, null și undefined sunt tipuri separate: o variabilă le acceptă doar dacă tipul ei le include.
  • optional chaining (?.): a?.b citește proprietatea doar dacă a nu este null sau undefined; altfel întreaga expresie dă undefined.
  • nullish coalescing (??): a ?? b dă a, iar dacă a este null sau undefined dă b; spre deosebire de ||, păstrează 0, „” și false.
  • as (type assertion): Îi spui compilatorului ce tip are o valoare, când știi mai mult decât el; nu face nicio conversie la rulare.
  • NonNullable: NonNullable<T> elimină null și undefined din tipul T.