keyof, typeof operatorlari va lookup types (T[K])

~20 daq · TypeScript · Generics

Ob'ektning istalgan xususiyatini oluvchi funksiya yozyapsiz. Xususiyat nomi string qabul qilsa — user.nomavjud ham o'tib ketadi. keyof faqat mavjud kalitlarni qabul qiladi.


keyof — ob'ekt kalitlari turi

keyof T — T turining barcha kalitlarini literal union sifatida beradi:

type Foydalanuvchi = {
  id:    number;
  ism:   string;
  email: string;
};

type FoydalanuvchiKalitlari = keyof Foydalanuvchi;
// "id" | "ism" | "email"
function xususiyat(user: Foydalanuvchi, kalit: keyof Foydalanuvchi) {
  return user[kalit];
}

xususiyat(user, "ism");   // ✅
xususiyat(user, "yosh");  // ❌ — "yosh" keyof Foydalanuvchi emas

keyof generic bilan

function olish<T, K extends keyof T>(ob: T, kalit: K): T[K] {
  return ob[kalit];
}

const user = { id: 1, ism: "Ali", faol: true };

olish(user, "id");    // number ✅
olish(user, "ism");   // string ✅
olish(user, "faol");  // boolean ✅
olish(user, "yosh");  // ❌ kompilyator xato

typeof — qiymatdan tur chiqarish

typeof TypeScript da tur kontekstida ishlatilsa — qiymatning turi:

const sozlamalar = {
  host:  "localhost",
  port:  5432,
  ssl:   false,
};

type Sozlamalar = typeof sozlamalar;
// { host: string; port: number; ssl: boolean }

function yangilash(yangi: Partial<typeof sozlamalar>): void {
  // ...
}

typeof + keyof birga

const rang = { qizil: "#e00", yashil: "#0e0", ko_k: "#00e" };

type RangKalitlari = keyof typeof rang;
// "qizil" | "yashil" | "ko_k"

function rangOl(kalit: keyof typeof rang): string {
  return rang[kalit];
}

rangOl("qizil");  // ✅ "#e00"
rangOl("sariq");  // ❌

Lookup types — T[K]

Ob'ekt turining xususiyat turini olish:

type Foydalanuvchi = { id: number; ism: string; email: string };

type IdTuri    = Foydalanuvchi["id"];    // number
type IsmTuri   = Foydalanuvchi["ism"];  // string
type IdYoIsm   = Foydalanuvchi["id" | "ism"]; // number | string
type Barchasi  = Foydalanuvchi[keyof Foydalanuvchi]; // number | string

Amaliy — ob'ektni filter qilish

function kalitlarOl<T extends object, K extends keyof T>(
  ob: T,
  kalitlar: K[]
): Pick<T, K> {
  const natija = {} as Pick<T, K>;
  kalitlar.forEach(k => { natija[k] = ob[k]; });
  return natija;
}

const user = { id: 1, ism: "Ali", email: "ali@mail.com", parol: "***" };
const xavfsiz = kalitlarOl(user, ["id", "ism", "email"]);
// { id: number; ism: string; email: string } — parol yo'q

Tez-tez uchraydigan xatolar

typeof ni runtime va compile-time da chalkashtirib yuborish:

// Runtime typeof — string qaytaradi
console.log(typeof "salom"); // "string"

// Compile-time typeof — tur qaytaradi
type T = typeof sozlamalar; // { host: string; port: number }

Ikkalasi bir xil yozuv — lekin context boshqacha.


Xulosa

keyof T         →  T ning barcha kalitlari ("id" | "ism" | "email")
typeof qiymat   →  qiymatning turi (tip kontekstda)
T[K]            →  T ning K kaliti turi (lookup)

// Birga
function olish<T, K extends keyof T>(o: T, k: K): T[K] { return o[k]; }
type Kalitlar = keyof typeof ob'ekt;

Keyingi dars

38-dars: Class — TypeScript da asoslar, JavaScript dan farqi