keyof în TypeScript

keyof T dă union-ul numelor de proprietăți ale lui T, de exemplu "nume" | "oras".

Sintaxă
type Chei = keyof Tip;        // union cu numele proprietăților
type K = keyof typeof obiect;

Ce face keyof

keyof ia un tip obiect și produce un union cu numele proprietăților lui, ca tipuri literale. Pentru interface Elev { nume: string; nota: number }, keyof Elev este "nume" | "nota". Dacă adaugi o proprietate în interfață, union-ul se actualizează singur.

Este folosit în funcții generice care primesc numele unei proprietăți (K extends keyof T), în mapped types ([K in keyof T]) și împreună cu typeof pentru a lua cheile unui obiect concret: keyof typeof setari.

Pentru un tip cu index signature [k: string]: X, keyof dă string | number (în JavaScript cheile numerice se convertesc la text). keyof există doar la compilare; la rulare, cheile se obțin cu Object.keys, care returnează string[], nu keyof T.

Exemple

Exemplul 1: Funcție care citește o proprietate după nume

interface Elev {
    nume: string;
    oras: string;
    nota: number;
}
type CheieElev = keyof Elev;     // "nume" | "oras" | "nota"

function afiseaza(e: Elev, chei: CheieElev[]): string {
    return chei.map((k) => `${k}=${e[k]}`).join(", ");
}

const ana: Elev = { nume: "Ana", oras: "Iași", nota: 10 };
console.log(afiseaza(ana, ["nume", "nota"]));
console.log(afiseaza(ana, ["oras"]));

Rezultat

nume=Ana, nota=10
oras=Iași

Exemplul 2: Cheie care nu există

interface Elev {
    nume: string;
    nota: number;
}
const k: keyof Elev = "varsta";
console.log(k);

Eroarea afișată de tsc

exemplu.mts(5,7): error TS2322: Type '"varsta"' is not assignable to type 'keyof Elev'.

Exemplul 3: keyof typeof pe un obiect concret

Tipul cheilor se ia direct din obiectul preturi, fără să fie scris de mână.

const preturi = { paine: 5, lapte: 7.5, oua: 12 };
type Produs = keyof typeof preturi;     // "paine" | "lapte" | "oua"

function total(cos: Partial<Record<Produs, number>>): number {
    let suma = 0;
    for (const p of Object.keys(cos) as Produs[]) {
        suma += preturi[p] * (cos[p] ?? 0);
    }
    return suma;
}

console.log(total({ paine: 2, oua: 1 }), "lei");

Rezultat

22 lei

Greșeli frecvente

  • Te aștepți ca Object.keys(obiect) să aibă tipul (keyof T)[]. Are string[], pentru că obiectul poate avea la rulare mai multe chei decât spune tipul; conversia cu as este responsabilitatea ta.
  • Scrii keyof obiect pe o valoare. keyof lucrează pe tipuri; pentru o valoare scrie keyof typeof obiect.

Comenzi înrudite

  • typeof (tip): În poziție de tip, typeof x dă tipul variabilei sau funcției x, ca să nu-l scrii de mână.
  • indexed access (T[K]): T[„cheie”] dă tipul unei proprietăți din T; T[number] dă tipul elementelor unui tablou.
  • mapped types: Construiesc un tip nou trecând prin fiecare cheie a altui tip: { [K in keyof T]: … }.
  • constrângeri generice (extends): T extends Tip limitează tipurile permise pentru T, ca funcția să poată folosi proprietățile lui Tip.
  • Record: Record<K, T> descrie un obiect ale cărui chei sunt K și ale cărui valori au toate tipul T.