13-bo‘lim

Utility turlari

Partial, Pick, Omit, Record va boshqalar; Omit ning tekshirilmaydigan kaliti va o'z turingizni yozish.

🕑 27 daqiqa o‘qish 📄 845 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Partial va Required
  2. Birinchi tuzoq: Readonly yuzaki
  3. Pick va Omit
  4. Ikkinchi tuzoq: Omit kalitni tekshirmaydi
  5. Record
  6. Union ustidagi utility turlar
  7. Funksiyadan tur olish
  8. as const bilan ro'yxatdan union
  9. O'z utility turingizni yozish
  10. Xulosa

TypeScript mavjud turdan yangi tur yasash uchun tayyor yordamchilar beradi. Ular utility turlar deb ataladi va hech qanday import talab qilmaydi.

Bu bobda ular bilan ishlaymiz, ikkita tuzoqni ko'ramiz va oxirida o'zimiznikini yozamiz.

Partial va Required #

TS
type Mahsulot = { nomi: string; narx: number; tavsif: string };

function yangila(m: Mahsulot, ozgarish: Partial<Mahsulot>): Mahsulot {
  return { ...m, ...ozgarish };
}

const m: Mahsulot = { nomi: "Olma", narx: 12000, tavsif: "shirin" };
console.log(yangila(m, { narx: 15000 }));
Terminal
tsx src/partial.ts
Natija
{ nomi: 'Olma', narx: 15000, tavsif: 'shirin' }

Partial<T> har bir maydonni ixtiyoriy qiladi. Bu - "faqat o'zgargan maydonlarni yubor" naqshi uchun aynan mos.

Required<T> teskarisini qiladi:

TS
type Sozlama = { port?: number; host?: string };
type Toliq = Required<Sozlama>;

const s: Toliq = { port: 8080, host: "localhost" };
console.log(s.port, s.host);
Terminal
tsx src/required.ts
Natija
8080 localhost
TS
type Sozlama = { port?: number; host?: string };
type Toliq = Required<Sozlama>;

const s: Toliq = { port: 8080 };
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/required2.ts(4,7): error TS2741: Property 'host' is missing in type
'{ port: number; }' but required in type 'Required<Sozlama>'.

Amalda bu juftlik ko'p uchraydi: foydalanuvchi Partial beradi, standart qiymatlar bilan birlashtirilgach Required chiqadi.

Birinchi tuzoq: Readonly yuzaki #

TS
type Dokon = { nomi: string; manzil: { shahar: string } };

const d: Readonly<Dokon> = {
  nomi: "Dokon",
  manzil: { shahar: "Toshkent" },
};

d.nomi = "Yangi";
d.manzil.shahar = "Samarqand";
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/readonly.ts(8,3): error TS2540: Cannot assign to 'nomi' because it is
a read-only property.

Faqat 8-qator xato berdi. 9-qator - ichki obyektning maydoni - jimgina o'tdi:

TS
type Dokon = { nomi: string; manzil: { shahar: string } };

const d: Readonly<Dokon> = {
  nomi: "Dokon",
  manzil: { shahar: "Toshkent" },
};

d.manzil.shahar = "Samarqand";
console.log(d.manzil.shahar);
Terminal
tsc --noEmit && echo "tsc: xato yo_q"
tsx src/readonly2.ts
Natija
tsc: xato yo_q
Samarqand

Readonly<T> faqat birinchi darajani qotiradi. Bu qoida Partial, Required va boshqalar uchun ham amal qiladi - hammasi yuzaki.

Chuqur variantini bob oxirida o'zimiz yozamiz.

Pick va Omit #

TS
type Mahsulot = {
  id: number;
  nomi: string;
  narx: number;
  tavsif: string;
};

type Qisqa = Pick<Mahsulot, "nomi" | "narx">;
type Yangi = Omit<Mahsulot, "id">;

const a: Qisqa = { nomi: "Olma", narx: 12000 };
const b: Yangi = { nomi: "Anor", narx: 25000, tavsif: "nordon" };

console.log(a.nomi, b.tavsif);
Terminal
tsx src/pick.ts
Natija
Olma nordon
TurMa'nosi
Pick<T, K>Faqat K kalitlarini olish
Omit<T, K>K kalitlaridan tashqari hammasini olish

Omit<Mahsulot, "id"> - ma'lumotlar bazasiga yangi yozuv qo'shish uchun juda mos: id ni baza o'zi beradi.

Ikkinchi tuzoq: Omit kalitni tekshirmaydi #

TS
type Mahsulot = { id: number; nomi: string };

type A = Omit<Mahsulot, "rang">;
type B = Pick<Mahsulot, "rang">;

const a: A = { id: 1, nomi: "Olma" };
console.log(a.nomi);
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/omit.ts(4,25): error TS2344: Type '"rang"' does not satisfy the
constraint 'keyof Mahsulot'.

Faqat 4-qator - Pick - xato berdi. 3-qatordagi Omit<Mahsulot, "rang"> jimgina o'tdi va A shunchaki Mahsulot ning o'ziga teng bo'lib qoldi.

Sabab - ularning e'lonlaridagi farq:

Natija
type Pick<T, K extends keyof T> = ...
type Omit<T, K extends keyof any> = ...

Pick kalit T da borligini talab qiladi, Omit esa istalgan kalitni qabul qiladi.

Mavjud bo'lmagan kalit berilganda Pick<Mahsulot, "rang"> K extends keyof T Kalit T da bo'lishi SHART TS2344 - darhol xato Maydon nomini o'zgartirsangiz, kompilyator sizni topadi Omit<Mahsulot, "rang"> K extends keyof any Istalgan kalit qabul qilinadi Xato yo'q - natija T ning o'zi Maydon nomini o'zgartirsangiz, Omit jim qoladi va maydon qaytadi Himoya type QatiyOmit<T, K extends keyof T> = Omit<T, K> Bir qatorlik o'rovchi - endi kalit tekshiriladi.
Omit ning yumshoqligi maydon qayta nomlanganda sezilmay qoladi
Omit qachon xavfli bo'ladi

Tasavvur qiling: Omit<Foydalanuvchi, "parol"> yozdingiz. Keyin kimdir maydonni parolHash deb qayta nomladi.

Omit hech narsa demaydi - va parolHash natijada qolib ketadi.

Shuning uchun maxfiy maydonni olib tashlash uchun Omit ga tayanmang. Pick bilan kerakli maydonlarni sanab chiqing - u har qanday o'zgarishda ovoz chiqaradi.

Record #

TS
type Daraja = "past" | "orta" | "yuqori";

const narxlar: Record<Daraja, number> = {
  past: 5000,
  orta: 12000,
  yuqori: 30000,
};

console.log(narxlar.orta);
Terminal
tsx src/record.ts
Natija
12000

Record<K, V> ning kuchi - u to'liq bo'lishni talab qiladi:

TS
type Daraja = "past" | "orta" | "yuqori";

const narxlar: Record<Daraja, number> = { past: 5000 };
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/record2.ts(3,7): error TS2739: Type '{ past: number; }' is missing
the following properties from type 'Record<Daraja, number>': orta, yuqori

Bu - 6-bobdagi never tekshiruvining obyekt varianti: unionga yangi a'zo qo'shsangiz, to'ldirilmagan Record lar darhol ko'rinadi.

Union ustidagi utility turlar #

TS
type Hamma = "olma" | "anor" | "uzum" | null;

type Qolgan = Exclude<Hamma, "uzum" | null>;
type Olingan = Extract<Hamma, "olma" | "shaftoli">;
type Bosh = NonNullable<Hamma>;

const a: Qolgan = "olma";
const b: Olingan = "olma";
const c: Bosh = "uzum";

console.log(a, b, c);
Terminal
tsx src/union.ts
Natija
olma olma uzum
TurNatija
Exclude<Hamma, "uzum" | null>"olma" | "anor"
Extract<Hamma, "olma" | "shaftoli">"olma"
NonNullable<Hamma>"olma" | "anor" | "uzum"

Extract da "shaftoli" Hamma da yo'q edi - u shunchaki natijaga tushmadi, xato bo'lmadi.

Funksiyadan tur olish #

TS
function yarat(nomi: string, narx: number) {
  return { nomi, narx, faol: true };
}

type Mahsulot = ReturnType<typeof yarat>;
type Args = Parameters<typeof yarat>;

const m: Mahsulot = { nomi: "Olma", narx: 12000, faol: false };
const a: Args = ["Anor", 25000];

console.log(m.nomi, a[1], yarat(...a).faol);
Terminal
tsx src/rettype.ts
Natija
Olma 25000 true

typeof yarat - qiymatdan tur olish. ReturnType esa undan qaytish turini ajratib beradi.

Bu naqsh juda foydali: Mahsulot turini alohida yozish shart emas, u funksiyaga bog'lanib turadi va funksiya o'zgarsa, o'zi ham o'zgaradi.

Promise ichidagi turni olish uchun Awaited:

TS
async function narxi(): Promise<number> {
  return 12000;
}

type N = Awaited<ReturnType<typeof narxi>>;

const n: N = 12000;
console.log(n.toFixed(2));
Terminal
tsx src/awaited.ts
Natija
12000.00

as const bilan ro'yxatdan union #

Bu - eng ko'p ishlatiladigan naqshlardan biri:

TS
const DARAJALAR = ["past", "orta", "yuqori"] as const;

type Daraja = (typeof DARAJALAR)[number];

const d: Daraja = "orta";
console.log(DARAJALAR.length, d);

for (const x of DARAJALAR) console.log(x);
Terminal
tsx src/asconst.ts
Natija
3 orta
past
orta
yuqori
TS
const DARAJALAR = ["past", "orta", "yuqori"] as const;
type Daraja = (typeof DARAJALAR)[number];

const d: Daraja = "juda";
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/asconst2.ts(4,7): error TS2322: Type '"juda"' is not assignable to
type '"past" | "orta" | "yuqori"'.

Nima bo'ldi:

QadamNatija
["past", ...]string[]
... as constreadonly ["past", "orta", "yuqori"]
(typeof D)[number]"past" | "orta" | "yuqori"

Bitta manbadan ham ro'yxat, ham tur chiqdi. Endi ro'yxatni tahrirlasangiz, tur o'zi yangilanadi - bu enum dan ham, ikkalasini alohida yozishdan ham yaxshiroq.

O'z utility turingizni yozish #

Utility turlar sehr emas - ular moslangan turlar (mapped types) orqali yozilgan:

TS
type MeningPartial<T> = { [K in keyof T]?: T[K] };
type Nullable<T> = { [K in keyof T]: T[K] | null };

type Mahsulot = { nomi: string; narx: number };

const a: MeningPartial<Mahsulot> = { nomi: "Olma" };
const b: Nullable<Mahsulot> = { nomi: null, narx: 12000 };

console.log(a.nomi, b.nomi, b.narx);
Terminal
tsx src/oz.ts
Natija
Olma null 12000

[K in keyof T] - "T ning har bir kaliti uchun". Partial ning haqiqiy e'loni ham aynan shunday.

Kalit nomini ham o'zgartirish mumkin:

TS
type Getterlar<T> = {
  [K in keyof T as `ol${Capitalize<string & K>}`]: () => T[K];
};

type Mahsulot = { nomi: string; narx: number };

const m: Getterlar<Mahsulot> = {
  olNomi: () => "Olma",
  olNarx: () => 12000,
};

console.log(m.olNomi(), m.olNarx());
Terminal
tsx src/getter.ts
Natija
Olma 12000

nomiolNomi, narxolNarx. Bu yerda uchta narsa birlashdi: kalitni qayta nomlash (as), shablon literal turi (`ol${...}`) va Capitalize.

Endi yuqorida va'da qilingan chuqur Readonly:

TS
type ChuqurReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object
    ? ChuqurReadonly<T[K]>
    : T[K];
};

type Dokon = { nomi: string; manzil: { shahar: string } };

declare const d: ChuqurReadonly<Dokon>;
d.manzil.shahar = "Samarqand";
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/chuqur.ts(10,10): error TS2540: Cannot assign to 'shahar' because it
is a read-only property.

T[K] extends object ? ... : ... - shartli tur. U "qiymat obyektmi?" deb so'raydi va obyekt bo'lsa o'zini qaytadan chaqiradi.

Tayyorini qidiring

Chuqur Readonly, chuqur Partial, RequireAtLeastOne kabi turlar allaqachon yozilgan:

PaketNima beradi
type-fest200 dan ortiq tayyor utility tur
ts-essentialsChuqur variantlar va boshqalar

O'zingiz yozish - tushunish uchun foydali. Ishlab chiqarishda esa sinalgan paketni olish tezroq va xavfsizroq.

Xulosa #

  • Utility turlar tayyor keladi - import qilish shart emas.
  • Partial<T> hamma maydonni ixtiyoriy, Required<T> hammasini majburiy qiladi.
  • Readonly<T> - va boshqa hamma utility tur - yuzaki; ichki obyektlar himoyalanmaydi.
  • Pick<T, K> kerakli kalitlarni oladi, Omit<T, K> esa keraksizlarini olib tashlaydi.
  • Omit mavjud bo'lmagan kalitni jimgina qabul qiladi, Pick esa TS2344 beradi.
  • Maxfiy maydonni olib tashlash uchun Omit emas, Pick ishlating - yoki Omit ni qat'iy o'rovchiga o'rang.
  • Record<K, V> barcha kalitlar to'ldirilishini talab qiladi.
  • Exclude, Extract, NonNullable - union ustida ishlaydi.
  • ReturnType<typeof f> va Parameters<typeof f> turni funksiyaga bog'lab qo'yadi.
  • as const + (typeof X)[number] bitta ro'yxatdan ham massiv, ham union beradi.
  • Utility turlar moslangan turlar ([K in keyof T]) orqali yozilgan - o'zingiznikini yozish qiyin emas.
  • Shartli tur (T extends U ? A : B) rekursiya bilan birga chuqur variantlarni yaratadi.
Amaliy topshiriq
  1. Partial<T> bilan "faqat o'zgarganini yuborish" funksiyasini yozing.
  2. Required<T> dan maydon tushirib qoldirib, TS2741 ni oling.
  3. Readonly<T> ning ichki obyektini o'zgartirib, tsc jim turishini tasdiqlang.
  4. Pick bilan uchta maydondan ikkitasini tanlang.
  5. Omit ga mavjud bo'lmagan kalit berib, xato yo'qligini ko'ring.
  6. Xuddi shu kalitni Pick ga berib, TS2344 ni oling.
  7. Record<Daraja, number> yozib, bitta kalitni tushirib qoldiring.
  8. ReturnType<typeof f> bilan funksiya natijasidan tur oling.
  9. as const massivdan union yasang va ro'yxatdan tashqari qiymat berib ko'ring.
  10. O'zingizning Nullable<T> turingizni yozing, keyin ChuqurReadonly<T> ni takrorlang.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.