


keyof получает тип допустимых ключей из типа объекта. Вместе с индексируемым типом T[K] он помогает написать функцию чтения свойства: переданный ключ должен существовать в типе объекта, а результат сохраняет тип конкретного поля. Это проверка на этапе компиляции, не валидация внешнего JSON.
У типа User два известных поля. Поэтому UserKey допускает только строковые литералы id и name.
type User = { id: number; name: string };
type UserKey = keyof User; // "id" | "name"
const user = { id: 7, name: "Анна" };
type ActualKey = keyof typeof user; // "id" | "name"
В первом случае User уже является типом. Во втором user является значением, поэтому typeof user сначала извлекает его тип, а keyof получает ключи. Это использование typeof в позиции типа; оно не создаёт проверку объекта во время выполнения программы.
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const id = getProperty(user, "id"); // number
const name = getProperty(user, "name"); // string
// getProperty(user, "email"); // ошибка проверки типов
Ограничение K extends keyof T связывает второй аргумент с первым. Возвращаемый T[K] обозначает тип свойства по этому ключу. Если вместо конкретного литерала передать ключ с объединением "id" | "name", результат будет number | string: компилятор не обязан знать, какое поле будет выбрано при выполнении.
Не расширяйте переменную ключа до произвольного string без необходимости. У значения const key = "name" тип достаточно узкий. Данные, пришедшие из адресной строки или формы, имеют другой уровень доверия и требуют проверки до вызова такой функции.
Тип { [key: string]: boolean } описывает произвольные строковые ключи, а его keyof имеет тип string | number. Причина числовой части связана с обращением к свойствам JavaScript: числовой ключ обычного объекта приводится к строке. Не переносите вывод о конечном наборе «id или name» на словарь с индексной сигнатурой.
Также Object.keys() во время выполнения и keyof на уровне типов решают разные задачи. Простое приведение результата Object.keys к массиву keyof может скрыть расхождение фактического объекта и его статического типа. Сначала определите, откуда объект пришёл и что гарантирует его форму.
Внешний JSON нужно проверить отдельно: существует ли объект, какие поля присутствуют и имеют ли они нужные типы. Утверждение as User не превращает непроверенные данные в корректного пользователя. Для функции выше полезно проверить вывод number и string, ошибку несуществующего ключа и объединение результатов при ключе-переменной.
На курсе TypeScript можно последовательно освоить такие связи типов. Если generic-функция уже разрослась, наставник по TypeScript на Mentoring.digital поможет отделить проверяемый контракт от небезопасных приведений.