is și is! în Dart

Verifică la rulare dacă o valoare are un anumit tip; după verificare, variabila poate fi folosită ca acel tip.

Sintaxă
valoare is Tip      // true dacă valoarea este de tipul Tip (sau un subtip)
valoare is! Tip     // true dacă NU este de tipul Tip

Ce face is și is!

x is String întoarce true dacă obiectul din x este un String sau un subtip al lui. is! este negația: x is! String înseamnă !(x is String).

După un if (x is String), Dart face promovare de tip (type promotion): în interiorul blocului, x este tratat ca String și poți folosi x.length fără conversii. Promovarea funcționează pentru variabile locale și parametri, nu pentru câmpuri publice (care s-ar putea schimba între verificare și folosire).

Analizorul te avertizează când verificarea este inutilă, de exemplu 5 is int, pentru că rezultatul se știe dinainte. În Dart 3, multe verificări de tip se scriu mai elegant cu pattern-uri într-un switch.

Exemple

Exemplul 1: Verificare și promovare de tip

Lista are tipul List<Object>. După fiecare is, valoarea se folosește direct ca tipul verificat.

void descrie(Object valoare) {
  if (valoare is String) {
    print('Text cu ${valoare.length} litere: ${valoare.toUpperCase()}');
  } else if (valoare is int) {
    print('Număr întreg, dublul este ${valoare * 2}');
  } else if (valoare is List) {
    print('Listă cu ${valoare.length} elemente');
  } else {
    print('Alt tip: ${valoare.runtimeType}');
  }
}

void main() {
  for (final v in <Object>['Iași', 21, [1, 2, 3], 3.5]) {
    descrie(v);
  }
}

Rezultat

Text cu 4 litere: IAȘI
Număr întreg, dublul este 42
Listă cu 3 elemente
Alt tip: double

Exemplul 2: is! pentru ieșire timpurie

Dacă valoarea nu este Map, funcția se oprește. După return, Dart știe că date este un Map.

String citesteNume(Object? date) {
  if (date is! Map<String, Object?>) {
    return 'date invalide';
  }
  final nume = date['nume'];
  return nume is String ? 'Nume: $nume' : 'lipsește numele';
}

void main() {
  print(citesteNume({'nume': 'Alexandra', 'oras': 'Arad'}));
  print(citesteNume({'oras': 'Arad'}));
  print(citesteNume('Alexandra'));
  print(citesteNume(null));
}

Rezultat

Nume: Alexandra
lipsește numele
date invalide
date invalide

Exemplul 3: Subtipuri și tipuri nullable

Un int este și num, și Object. null nu este niciunul dintre ele: el are tipul Null, care intră doar în tipurile cu ?.

void verifica(Object? x) {
  print('$x: num=${x is num}, int=${x is int}, double=${x is double}, Object=${x is Object}');
}

void main() {
  verifica(7);
  verifica(7.5);
  verifica(null);
}

Rezultat

7: num=true, int=true, double=false, Object=true
7.5: num=true, int=false, double=true, Object=true
null: num=false, int=false, double=false, Object=false

Greșeli frecvente

  • Să aștepți promovare pentru un câmp: if (this.nota is int) nota + 1 poate da eroare. Copiază câmpul într-o variabilă locală (final n = nota;) sau folosește un câmp privat final.
  • Verificări inutile ('abc' is String): Unnecessary type check; the result is always 'true'.
  • !x is String în loc de x is! String: prima formă aplică ! lui x, nu verificării.

Comenzi înrudite

  • as: Spune că o valoare are un anumit tip (cast); dacă nu are, aruncă TypeError. Tot as dă un prefix unui import.
  • Object?: Tipul de bază al tuturor valorilor din Dart, inclusiv null; varianta sigură a lui dynamic.
  • pattern-uri (destructurare): Desfac o valoare (record, listă, map, obiect) în variabile separate, într-o singură declarație.
  • switch: Alege un bloc de cod după valoarea sau forma unei expresii; în Dart 3 fiecare case este un pattern.
  • dynamic: Tipul care dezactivează verificarea statică: orice metodă se poate apela, verificarea se face la rulare.