typedef în Dart

Funcții Dart 1.0

Dă un nume (alias) unui tip, de obicei unui tip de funcție sau unui tip generic lung.

Sintaxă
typedef Nume = TipReturnat Function(Parametri);
typedef Nume = OriceTip;            // Dart 2.13
typedef Nume<T> = Map<String, T>;

Ce face typedef

typedef creează un alias: un nume nou pentru un tip existent. Cel mai des se folosește pentru tipuri de funcții, care altfel se scriu lung: typedef Validator = String? Function(String valoare);. După aceea scrii Validator peste tot.

Din Dart 2.13, aliasul poate fi pentru orice tip, nu doar pentru funcții: typedef Catalog = Map<String, List<int>>;. Aliasul poate avea și parametri generici.

Aliasul nu creează un tip nou: Catalog și Map<String, List<int>> sunt exact același tip. Dacă vrei un tip separat, care nu se amestecă cu cel original, folosește extension type sau o clasă.

Exemple

Exemplul 1: Alias pentru un tip de funcție

Validator este o funcție care întoarce un mesaj de eroare sau null.

typedef Validator = String? Function(String valoare);

String? nuEGol(String v) => v.trim().isEmpty ? 'câmpul este obligatoriu' : null;
String? esteEmail(String v) => v.contains('@') ? null : 'email invalid';

void valideaza(String valoare, List<Validator> reguli) {
  for (final regula in reguli) {
    final eroare = regula(valoare);
    if (eroare != null) {
      print('"$valoare": $eroare');
      return;
    }
  }
  print('"$valoare": valid');
}

void main() {
  final reguli = [nuEGol, esteEmail];
  valideaza('', reguli);
  valideaza('ana.exemplu.ro', reguli);
  valideaza('ana@exemplu.ro', reguli);
}

Rezultat

"": câmpul este obligatoriu
"ana.exemplu.ro": email invalid
"ana@exemplu.ro": valid

Exemplul 2: Alias pentru un tip lung

Catalog este doar alt nume pentru map-ul cu liste de note: compararea celor două tipuri dă true.

typedef Catalog = Map<String, List<int>>;

double mediaElevului(Catalog c, String elev) {
  final note = c[elev] ?? [];
  return note.isEmpty ? 0 : note.reduce((a, b) => a + b) / note.length;
}

void main() {
  final Catalog clasa = {'Ana': [10, 9], 'Paul': [7, 8, 6]};
  print(Catalog == Map<String, List<int>>);
  print('Ana: ${mediaElevului(clasa, 'Ana')}, Paul: ${mediaElevului(clasa, 'Paul')}');
}

Rezultat

true
Ana: 9.5, Paul: 7.0

Exemplul 3: typedef generic

Transformare<T> se poate folosi cu orice tip.

typedef Transformare<T> = T Function(T);

List<T> aplicaDeDouaOri<T>(List<T> valori, Transformare<T> f) =>
    valori.map((v) => f(f(v))).toList();

void main() {
  print(aplicaDeDouaOri<int>([1, 2, 3], (x) => x * 10));
  print(aplicaDeDouaOri<String>(['da'], (s) => '$s!'));
}

Rezultat

[100, 200, 300]
[da!!]

Greșeli frecvente

  • Să crezi că typedef creează un tip nou, separat: typedef Lei = double; acceptă orice double. Pentru siguranță folosește extension type.
  • Sintaxa veche typedef int Operatie(int a, int b); încă merge, dar forma cu = și Function este cea recomandată.
  • Alias-uri pentru tipuri scurte și clare: typedef Text = String; doar încurcă cititorul.

Comenzi înrudite

  • funcții: Blocuri de cod cu nume, care primesc parametri și returnează o valoare; în Dart sunt și obiecte.
  • generics: Clase și funcții cu tipuri ca parametri (<T>), care funcționează la fel pentru orice tip, păstrând verificarea tipurilor.
  • extension type: Un tip nou, verificat la compilare, care la rulare este doar o valoare existentă (de ex. un int), fără cost.