keyof T - тип-об'єднання всіх ключів типу T:
interface User {
id: number;
name: string;
email: string;
}
type UserKey = keyof User; // 'id' | 'name' | 'email'
Головне застосування - функції, що працюють з ключами об'єкта безпечно:
function getField<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user: User = { id: 1, name: 'Оля', email: 'olia@example.com' };
getField(user, 'name'); // string
getField(user, 'id'); // number
getField(user, 'phone'); // помилка: 'phone' немає в keyof User
Тип повернення T[K] точно відповідає переданому ключу - не string | number, а саме тип цього поля.
Інші застосування:
- сортування й групування таблиць за назвою колонки:
sortBy<T>(items: T[], key: keyof T); - перелік дозволених полів для фільтрів, форм, експорту;
- основа mapped types:
{ [K in keyof T]: ... }.
Особливості:
- з індексною сигнатурою
keyofдає ширший тип. Для{ [key: string]: number }результат -string | number, бо в JavaScript числові ключі об'єкта перетворюються на рядки (obj[1]- те саме, щоobj['1']); - для масивів
keyof string[]міститьnumberі назви методів масиву ('length' | 'push' | ...); - лише ключі типу, а не значення:
keyofпрацює з типами. Щоб отримати ключі значення, потрібнеkeyof typeof config.
Пастка з Object.keys: Object.keys(user) повертає string[], а не (keyof User)[]. Це навмисно: через структурну типізацію в об'єкті під час виконання можуть бути й інші поля, яких немає в типі. Тому for (const key of Object.keys(user)) user[key] - помилка типу, і доводиться або звужувати ключ, або використовувати Object.entries.