Remaparea Cheilor în Mapped Types prin Clauza as (Key Remapping) în TypeScript

Ghid complet pentru Key Remapping în Mapped Types (TypeScript 4.1+): redenumirea cheilor cu clauza as, combinarea cu Template Literal Types și filtrarea proprietăților prin never.

Sintaxă
type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] };

În versiunile mai vechi de TypeScript, un Mapped Type putea crea un nou tip doar păstrând exact numele cheilor originale (cum face Partial<T> sau Readonly<T>). Începând cu TypeScript 4.1, clauza as din mapped types permite remaparea cheilor (Key Remapping): transformarea numelor proprietăților prin expresii de tip șir, filtrarea cheilor sau inversarea asocierilor cheie-valoare.

Generarea automată de Getters folosind Key Remapping
interface Persoana {
    nume: string;
    varsta: number;
    oras: string;
}

// Transformăm fiecare proprietate 'prop' într-o metodă 'getProp()':
type CreazaGetters<T> = {
    [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type PersoanaGetters = CreazaGetters<Persoana>;
// Rezultat inferat automat:
// {
//     getNume: () => string;
//     getVarsta: () => number;
//     getOras: () => string;
// }

Filtrarea Cheilor prin Remapare la never

Dacă o cheie este remapată la tipul never, TypeScript elimină complet acea proprietate din tipul rezultat. Aceasta este modalitatea modernă și curată de a crea filtre avansate pe proprietăți:

Păstrarea exclusivă a metodelor dintr-o clasă
// Extrage doar proprietățile a căror valoare este o funcție:
type DoarFunctii<T> = {
    [K in keyof T as T[K] extends Function ? K : never]: T[K];
};

interface ServiciuUtilizator {
    id: number;
    nume: string;
    salveaza(): Promise<void>;
    sterge(id: number): boolean;
}

type Actiuni = DoarFunctii<ServiciuUtilizator>;
// Rezultat:
// {
//     salveaza: () => Promise<void>;
//     sterge: (id: number) => boolean;
// } (proprietățile 'id' și 'nume' au fost filtrate!)

Remaparea Cheilor peste Uniuni Discriminate

Puteți folosi remaparea cheilor pentru a transforma un array sau o uniune de evenimente într-un dicționar indexat după discriminant:

type Eveniment = 
    | { tip: 'click'; x: number; y: number }
    | { tip: 'tastatura'; tasta: string };

type HandlerEvenimente = {
    [E in Eveniment as E['tip']]: (ev: E) => void;
};

// Rezultat:
// {
//     click: (ev: { tip: 'click'; x: number; y: number }) => void;
//     tastatura: (ev: { tip: 'tastatura'; tasta: string }) => void;
// }