Урок 04

keyof и typeof

keyof

Возвращает union всех ключей типа:

type User = {
    name: string;
    age: number;
    email: string;
};

type UserKeys = keyof User;
// 'name' | 'age' | 'email'

Использование

Безопасный доступ к свойству

function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}

const user = { name: 'Алиса', age: 25 };
getValue(user, 'name'); // string
getValue(user, 'age');  // number
getValue(user, 'xxx');  // ошибка

Проверка ключа

function hasKey<T extends object>(obj: T, key: string): key is keyof T {
    return key in obj;
}

Ключи для обновления

function update<T, K extends keyof T>(obj: T, key: K, value: T[K]): T {
    return { ...obj, [key]: value };
}

update(user, 'name', 'Боб'); // ок
update(user, 'name', 42);    // ошибка

keyof на массиве

type Arr = string[];
type Keys = keyof Arr;
// number | 'length' | 'push' | 'pop' | ...

keyof на union

type A = { a: string };
type B = { b: number };

type Keys = keyof (A | B); // never

Для union — только общие ключи. У A | B общих нет.

keyof с пересечением

type Keys = keyof (A & B);
// 'a' | 'b'

typeof

Возвращает тип значения:

const user = { name: 'Алиса', age: 25 };

type User = typeof user;
// { name: string; age: number }

typeof функции

function add(a: number, b: number) {
    return a + b;
}

type Add = typeof add;
// (a: number, b: number) => number

Комбинация

const config = {
    apiUrl: 'https://api.example.com',
    timeout: 5000,
};

type Config = typeof config;
type ConfigKey = keyof typeof config;
// 'apiUrl' | 'timeout'

as const

const STATUS = {
    IDLE: 'idle',
    LOADING: 'loading',
    SUCCESS: 'success',
} as const;

type Status = typeof STATUS[keyof typeof STATUS];
// 'idle' | 'loading' | 'success'

as const делает значения литеральными, а keyof typeof даёт union.

Практика: enum через объект

export const Role = {
    Admin: 'admin',
    User: 'user',
    Guest: 'guest',
} as const;

export type Role = typeof Role[keyof typeof Role];
  • Есть объект для итерации
  • Есть тип
  • Нет runtime-кода как у enum

Практика: ключи формы

type Form = {
    name: string;
    email: string;
    password: string;
};

function validateField(field: keyof Form, value: string) {
    // ...
}

validateField('name', 'Алиса'); // ок
validateField('xxx', 'А');      // ошибка

Итоги

  • keyof — union ключей
  • typeof — тип значения
  • T[K] — тип значения по ключу
  • Комбинация даёт мощные утилиты
  • as const + keyof typeof — замена enum