interface în TypeScript

Descrie forma unui obiect: ce proprietăți are, de ce tip sunt și ce metode are.

Sintaxă
interface Nume {
    proprietate: Tip;
    optionala?: Tip;
    readonly fixa: Tip;
    metoda(x: Tip): TipRezultat;
}
interface Copil extends Parinte { ... }

Ce face interface

O interface dă un nume formei unui obiect. Spune ce proprietăți trebuie să existe, ce tip are fiecare și ce metode are obiectul. Orice obiect cu proprietățile cerute se potrivește cu interfața, chiar dacă nu a fost creat dintr-o clasă (TypeScript compară forma, nu numele: structural typing).

O proprietate cu ? poate lipsi, iar una readonly nu se poate modifica după creare. O interfață poate extinde una sau mai multe interfețe cu extends, preluând toate proprietățile lor. O clasă poate promite că respectă o interfață cu implements.

Interfețele există doar la compilare: dispar complet din JavaScript-ul generat. Două declarații interface cu același nume se unesc (declaration merging), lucru folosit pentru a completa tipurile unor biblioteci. Diferențele față de type sunt pe pagina interface vs type.

Exemple

Exemplul 1: Interfață pentru un elev

interface Elev {
    readonly id: number;
    nume: string;
    oras: string;
    note: number[];
    email?: string;
    medie(): number;
}

const ana: Elev = {
    id: 1,
    nume: "Ana",
    oras: "Iași",
    note: [9, 10, 8],
    medie() {
        return this.note.reduce((s, n) => s + n, 0) / this.note.length;
    },
};

console.log(`${ana.nume} din ${ana.oras}: ${ana.medie().toFixed(2)}`);
console.log("email:", ana.email ?? "lipsă");

Rezultat

Ana din Iași: 9.00
email: lipsă

Exemplul 2: Interfață care extinde altă interfață

interface Persoana {
    nume: string;
    varsta: number;
}
interface Profesor extends Persoana {
    materie: string;
}

function prezinta(p: Persoana): string {
    return `${p.nume}, ${p.varsta} ani`;
}

const prof: Profesor = { nume: "Ion Ionescu", varsta: 45, materie: "informatică" };
console.log(prezinta(prof));        // un Profesor este și o Persoana
console.log(`predă ${prof.materie}`);

Rezultat

Ion Ionescu, 45 ani
predă informatică

Exemplul 3: Proprietate lipsă și proprietate în plus

Unui obiect literal îi lipsește oras și are o proprietate pe care interfața nu o cunoaște (clasa). tsc raportează prima problemă găsită.

interface Elev {
    nume: string;
    oras: string;
}
const e1: Elev = { nume: "Ana" };
const e2: Elev = { nume: "Mihai", oras: "Cluj", clasa: "a X-a" };
console.log(e1, e2);

Eroarea afișată de tsc

exemplu.mts(5,7): error TS2741: Property 'oras' is missing in type '{ nume: string; }' but required in type 'Elev'.
exemplu.mts(6,49): error TS2353: Object literal may only specify known properties, and 'clasa' does not exist in type 'Elev'.

Greșeli frecvente

  • Încerci să verifici la rulare cu x instanceof Elev când Elev este o interfață. Interfețele nu există la rulare; folosește un predicat de tip.
  • Pui ; sau , amestecat: ambele separatoare sunt permise între proprietăți, dar alege unul și păstrează-l.
  • Declari din greșeală aceeași interfață de două ori în același fișier; se unesc fără avertisment și obiectele trebuie să aibă proprietățile din ambele.

Comenzi înrudite

  • type (alias de tip): Dă un nume oricărui tip: obiect, union, tuple, funcție sau un tip calculat din alte tipuri.
  • interface vs type: Când alegi interface și când type: pentru obiecte sunt aproape echivalente, dar au câteva diferențe importante.
  • implements: O clasă promite că respectă una sau mai multe interfețe; tsc verifică dacă are toți membrii ceruți.
  • readonly: Marchează o proprietate care primește valoare o singură dată și nu mai poate fi modificată după aceea.
  • index signatures: Descrie obiecte cu chei necunoscute dinainte: [cheie: string]: Tip, sau Record<string, Tip>.