13-bo‘lim
Utility turlari
Partial, Pick, Omit, Record va boshqalar; Omit ning tekshirilmaydigan kaliti va o'z turingizni yozish.
Ushbu bo‘lim mundarijasi
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 #
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 }));
tsx src/partial.ts
{ 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:
type Sozlama = { port?: number; host?: string };
type Toliq = Required<Sozlama>;
const s: Toliq = { port: 8080, host: "localhost" };
console.log(s.port, s.host);
tsx src/required.ts
8080 localhost
type Sozlama = { port?: number; host?: string };
type Toliq = Required<Sozlama>;
const s: Toliq = { port: 8080 };
tsc --noEmit 2>&1 | fold -sw 74
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 #
type Dokon = { nomi: string; manzil: { shahar: string } };
const d: Readonly<Dokon> = {
nomi: "Dokon",
manzil: { shahar: "Toshkent" },
};
d.nomi = "Yangi";
d.manzil.shahar = "Samarqand";
tsc --noEmit 2>&1 | fold -sw 74
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:
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);
tsc --noEmit && echo "tsc: xato yo_q"
tsx src/readonly2.ts
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 #
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);
tsx src/pick.ts
Olma nordon
| Tur | Ma'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 #
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);
tsc --noEmit 2>&1 | fold -sw 74
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:
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.
Omit qachon xavfli bo'ladiTasavvur 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 #
type Daraja = "past" | "orta" | "yuqori";
const narxlar: Record<Daraja, number> = {
past: 5000,
orta: 12000,
yuqori: 30000,
};
console.log(narxlar.orta);
tsx src/record.ts
12000
Record<K, V> ning kuchi - u to'liq bo'lishni talab
qiladi:
type Daraja = "past" | "orta" | "yuqori";
const narxlar: Record<Daraja, number> = { past: 5000 };
tsc --noEmit 2>&1 | fold -sw 74
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 #
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);
tsx src/union.ts
olma olma uzum
| Tur | Natija |
|---|---|
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 #
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);
tsx src/rettype.ts
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:
async function narxi(): Promise<number> {
return 12000;
}
type N = Awaited<ReturnType<typeof narxi>>;
const n: N = 12000;
console.log(n.toFixed(2));
tsx src/awaited.ts
12000.00
as const bilan ro'yxatdan union #
Bu - eng ko'p ishlatiladigan naqshlardan biri:
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);
tsx src/asconst.ts
3 orta
past
orta
yuqori
const DARAJALAR = ["past", "orta", "yuqori"] as const;
type Daraja = (typeof DARAJALAR)[number];
const d: Daraja = "juda";
tsc --noEmit 2>&1 | fold -sw 74
src/asconst2.ts(4,7): error TS2322: Type '"juda"' is not assignable to
type '"past" | "orta" | "yuqori"'.
Nima bo'ldi:
| Qadam | Natija |
|---|---|
["past", ...] | string[] |
... as const | readonly ["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:
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);
tsx src/oz.ts
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:
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());
tsx src/getter.ts
Olma 12000
nomi → olNomi, narx → olNarx. Bu yerda uchta narsa
birlashdi: kalitni qayta nomlash (as), shablon literal turi
(`ol${...}`) va Capitalize.
Endi yuqorida va'da qilingan chuqur Readonly:
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";
tsc --noEmit 2>&1 | fold -sw 74
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.
Chuqur Readonly, chuqur Partial, RequireAtLeastOne kabi
turlar allaqachon yozilgan:
| Paket | Nima beradi |
|---|---|
type-fest | 200 dan ortiq tayyor utility tur |
ts-essentials | Chuqur 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.Omitmavjud bo'lmagan kalitni jimgina qabul qiladi,PickesaTS2344beradi.- Maxfiy maydonni olib tashlash uchun
Omitemas,Pickishlating - yokiOmitni qat'iy o'rovchiga o'rang. Record<K, V>barcha kalitlar to'ldirilishini talab qiladi.Exclude,Extract,NonNullable- union ustida ishlaydi.ReturnType<typeof f>vaParameters<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.
Partial<T>bilan "faqat o'zgarganini yuborish" funksiyasini yozing.Required<T>dan maydon tushirib qoldirib,TS2741ni oling.Readonly<T>ning ichki obyektini o'zgartirib,tscjim turishini tasdiqlang.Pickbilan uchta maydondan ikkitasini tanlang.Omitga mavjud bo'lmagan kalit berib, xato yo'qligini ko'ring.- Xuddi shu kalitni
Pickga berib,TS2344ni oling. Record<Daraja, number>yozib, bitta kalitni tushirib qoldiring.ReturnType<typeof f>bilan funksiya natijasidan tur oling.as constmassivdan union yasang va ro'yxatdan tashqari qiymat berib ko'ring.- O'zingizning
Nullable<T>turingizni yozing, keyinChuqurReadonly<T>ni takrorlang.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.