Treci la conținutul principal

Semnături de index în TypeScript

O semnătură de index îți permite să descrii un obiect ale cărui nume de proprietăți nu le cunoști dinainte, spunând totuși ce tip trebuie să aibă fiecare valoare.


Înțelegerea semnăturilor de index în TypeScript

Semnăturile de index îți oferă o modalitate de a tipiza obiecte cu nume de proprietăți dinamice fără a pierde siguranța tipurilor.

Ele îi spun lui TypeScript ce tip de valoare se obține atunci când citești o proprietate cu notația cu paranteze drepte (obj[key]), chiar și atunci când numele exacte ale proprietăților nu sunt cunoscute dinainte.

Idei principale:

  • Acces dinamic la proprietăți: lucrezi cu obiecte care au orice nume de proprietăți.
  • Siguranța tipurilor: fiecare proprietate dinamică trebuie să conțină același fel de valoare.
  • Structuri de date flexibile: modelezi dicționare, hărți și alte tabele de căutare.
  • Erori timpurii: greșelile legate de tipurile valorilor sunt prinse la compilare.

Semnături de index de bază

Semnături de index de tip string. Folosește o semnătură de index atunci când nu cunoști dinainte numele proprietăților, dar cunoști forma valorilor.

Sintaxa folosește paranteze drepte: [key: type] descrie tipul numelor de proprietăți (cheile), iar după două puncte vine tipul valorilor pe care le pot conține acele proprietăți.

Semnături de index numerice. TypeScript acceptă atât chei numerice, cât și chei de tip string.

Notă: În JavaScript, toate cheile obiectelor sunt stocate ca string-uri, chiar și cele numerice. TypeScript le deosebește totuși pentru a ajuta la depistarea erorilor de logică atunci când confunzi tablourile cu obiectele.

Semnătură de index de tip string

StringDictionary acceptă orice cheie de tip string, dar fiecare valoare trebuie să fie un string. Citirea, adăugarea și actualizarea cheilor funcționează, în timp ce atribuirea unui număr este o eroare.

Prompt
Arată o semnătură de index de tip string cu o interfață StringDictionary ale cărei chei sunt string-uri și ale cărei valori sunt string-uri. Creează un obiect names de acest tip cu firstName: "Alice", lastName: "Smith" și cheia "100" asociată valorii "O sută", afișează cele trei valori folosind accesul cu paranteze drepte, apoi adaugă o cheie age cu string-ul "30". Lasă o linie comentată care arată că atribuirea numărului 30 ar fi o eroare de tip.
Ieșire: program TypeScript și rezultatul capturat

Semnătură de index numerică

NumberDictionary folosește chei numerice. Deoarece tipul valorii este any, fiecare intrare poate conține un alt fel de valoare.

Prompt
Arată o semnătură de index numerică cu o interfață NumberDictionary ale cărei chei sunt numere și ale cărei valori sunt any. Creează un obiect scores cu 0: "Zero", 1: 100 și 2: true, afișează cele trei intrări după indicele numeric, apoi adaugă indicele 3 care conține obiectul { passed: true }.
Ieșire: program TypeScript și rezultatul capturat

Tipare avansate de semnături de index

Tipuri de proprietăți mixte. Poți combina o semnătură de index cu proprietăți numite explicit. Proprietățile numite sunt obligatorii; tot restul trebuie să corespundă semnăturii de index.

Important: Când combini proprietăți explicite cu o semnătură de index, tipul fiecărei proprietăți explicite trebuie să poată fi atribuit tipului de valoare al semnăturii de index.

Semnături de index readonly. Adaugă readonly la o semnătură de index pentru a împiedica modificarea valorilor după crearea obiectului.

Pentru restrângerea mulțimilor de chei și transformarea formelor, vezi lecția despre tipuri mapate.

Tipuri de proprietăți mixte

UserInfo cere name și age și permite orice altă proprietate atâta timp cât valoarea ei este un string sau un number.

Prompt
Combină proprietăți explicite cu o semnătură de index într-o interfață UserInfo: name: string și age: number obligatorii, plus o semnătură [key: string]: string | number pentru orice altă proprietate. Creează un obiect user valid cu name: "Alice", age: 30, address: "123 Main St" și zipCode: 12345. Adaugă un invalidUser comentat care arată că age: "thirty" și isAdmin: true ar fi fiecare erori de tip. Fișierul nu afișează nimic.
Ieșire: program TypeScript și rezultatul capturat

Semnătură de index readonly

Citirea lui names[0] este permisă, dar scrierea la orice index al unui ReadOnlyStringArray este o eroare de compilare.

Prompt
Declară o interfață ReadOnlyStringArray cu o semnătură de index readonly [index: number]: string. Atribuie tabloul ["Alice", "Bob", "Charlie"] unei variabile names de acest tip, afișează names[0] și lasă o atribuire comentată către names[0] care explică faptul că scrierea printr-o semnătură de index readonly este o eroare de tip.
Ieșire: program TypeScript și rezultatul capturat

Exemple din lumea reală

Gestionarea răspunsurilor de API. Semnăturile de index sunt utile pentru răspunsurile de API în care numele resurselor și câmpurile suplimentare de metadate nu sunt fixe.

Gestionarea răspunsurilor de API

ApiResponse<T> permite ca data să conțină orice nume de resursă asociat unui tablou de T și permite ca meta să poarte câmpuri suplimentare pe lângă page și total.

Prompt
Modelează un răspuns de API generic cu semnături de index: o interfață ApiResponse<T> al cărei data asociază orice nume de resursă ([resourceType: string]) cu T[], și al cărei meta are page: number, total: number plus o semnătură [key: string]: any pentru metadate suplimentare. Declară o interfață User (id, name, email), construiește un apiResponse: ApiResponse<User> cu doi utilizatori (Alice și Bob) și meta page: 1, total: 2, timestamp: "2023-01-01T00:00:00Z", apoi afișează numele primului utilizator.
Ieșire: program TypeScript și rezultatul capturat

Bune practici

Ce să faci:

  • Folosește semnături de index pentru colecții cu chei dinamice.
  • Combină-le cu proprietăți explicite pentru câmpurile pe care le cunoști.
  • Păstrează tipurile valorilor specifice — evită any.
  • Folosește readonly atunci când valorile nu trebuie să se schimbe.

Ce să eviți:

  • Să recurgi la o semnătură de index atunci când cheile sunt cunoscute — preferă o interfață fixă.
  • Să uiți că fiecare proprietate, inclusiv cele explicite, trebuie să se potrivească cu tipul de valoare al semnăturii de index.
  • Să reinventezi tipurile mapate — folosește-le pentru transformări de formă.

Capcane frecvente

O greșeală frecventă este declararea unei proprietăți explicite al cărei tip nu se potrivește cu semnătura de index. Lărgește tipul de valoare al semnăturii de index pentru a rezolva problema.

Conflict între tipul proprietății și tipul de index

ConflictingTypes eșuează pentru că name: string nu se potrivește cu semnătura de index number; FixedTypes lărgește tipul valorii la number | string, astfel încât ambele proprietăți sunt permise.

script.ts
  interface ConflictingTypes {
    [key: string]: number;
    name: string; // Error: not assignable to string index type 'number'
  }

  interface FixedTypes {
    [key: string]: number | string;
    name: string;  // OK
    age: number;   // OK
  }

Semnături de index vs Record

Folosește o semnătură de index atunci când cheile sunt flexibile sau dinamice și când ai nevoie să adaugi și alte proprietăți.

Folosește Record<K, T> pentru asocieri simple și concise de la un tip de cheie la un tip de valoare.

Semnătură de index și Record una lângă alta

StringMap și StringRecord descriu aceeași formă — orice cheie de tip string asociată unei valori de tip string — scrisă în două moduri diferite.

script.ts
// Index signature
interface StringMap {
  [key: string]: string;
}

// Record
type StringRecord = Record<string, string>;

Concluzie

Folosește semnături de index atunci când cheile sunt dinamice, dar forma valorilor este consecventă.

Combină-le cu proprietăți explicite ori de câte ori este posibil și vezi lecțiile despre tipuri mapate și tipuri utilitare pentru transformări mai avansate.