14-bo‘lim
Literal turlar va enum
Tur kengayishi, satisfies operatori, enum ning ish vaqtidagi izi va shablon literal turlari.
Ushbu bo‘lim mundarijasi
3-bobda const va let ning turlari boshqacha ekanini ko'rdik.
Bu bobda o'sha hodisani - tur kengayishini - to'liq
o'rganamiz, satisfies operatorini tanishtiramiz va enum ni
literal union bilan solishtiramiz.
Tur kengayishi #
const a = "Olma";
let b = "Olma";
const x: "Olma" = a;
const y: "Olma" = b;
tsc --noEmit 2>&1 | fold -sw 74
src/keng.ts(5,7): error TS2322: Type 'string' is not assignable to type
'"Olma"'.
a - "Olma" literali, b esa string. let qayta
tayinlanishi mumkin, shuning uchun TypeScript turni
kengaytiradi.
Kengayish obyekt literalida ham bo'ladi #
Bu esa allaqachon ko'rgan naqshimizni buzadi:
type Naqd = { usul: "naqd"; miqdor: number };
const xom = { usul: "naqd", miqdor: 12000 };
const t: Naqd = xom;
tsc --noEmit 2>&1 | fold -sw 74
src/keng2.ts(4,7): error TS2322: Type '{ usul: string; miqdor: number; }'
is not assignable to type 'Naqd'.
Types of property 'usul' are incompatible.
Type 'string' is not assignable to type '"naqd"'.
xom const bo'lsa ham, uning maydonlari o'zgartirilishi
mumkin (xom.usul = "karta"). Shuning uchun usul string
ga kengaydi.
Uchta yechim bor:
type Naqd = { usul: "naqd"; miqdor: number };
const a: Naqd = { usul: "naqd", miqdor: 12000 };
const b = { usul: "naqd" as const, miqdor: 25000 };
const c = { usul: "naqd", miqdor: 30000 } as const;
const t1: Naqd = a;
const t2: Naqd = b;
const t3: Naqd = c;
console.log(t1.miqdor, t2.miqdor, t3.miqdor);
tsx src/keng3.ts
12000 25000 30000
| Yechim | Ta'siri |
|---|---|
const a: Naqd = {...} | Tur oldindan ma'lum - kengayish yo'q |
usul: "naqd" as const | Faqat bitta maydon qotadi |
{...} as const | Barcha maydonlar readonly va literal |
satisfies operatori #
Turni annotatsiya bilan berish bitta yon ta'sirga ega - o'zgaruvchi o'sha turga aylanadi:
type Narxlar = Record<string, number>;
const narxlar: Narxlar = { olma: 12000, anor: 25000 };
console.log(narxlar.olma.toFixed(0));
console.log(narxlar.yoq.toFixed(0));
tsc --noEmit && echo "tsc: xato yo_q"
tsx src/satis.ts 2>&1 | grep -oE "(^12000|TypeError.*)" | head -2
tsc: xato yo_q
12000
TypeError: Cannot read properties of undefined (reading 'toFixed')
narxlar endi Record<string, number> - unda istalgan
kalit bor deb hisoblanadi. Aniq kalitlar haqidagi bilim
yo'qoldi.
satisfies tekshiradi, lekin turni almashtirmaydi:
type Narxlar = Record<string, number>;
const narxlar = {
olma: 12000,
anor: 25000,
} satisfies Narxlar;
console.log(narxlar.olma.toFixed(0));
console.log(narxlar.yoq);
tsc --noEmit 2>&1 | fold -sw 74
src/satis2.ts(9,21): error TS2339: Property 'yoq' does not exist on type
'{ olma: number; anor: number; }'.
Tekshiruv esa baribir ishlaydi:
type Narxlar = Record<string, number>;
const narxlar = {
olma: 12000,
anor: "yigirma besh ming",
} satisfies Narxlar;
tsc --noEmit 2>&1 | fold -sw 74
src/satis3.ts(5,3): error TS2322: Type 'string' is not assignable to type
'number'.
: yoki satisfies - qaysi biri| Maqsad | Tanlov |
|---|---|
| Qiymat shu turga mos bo'lsin | satisfies |
| Qiymat aynan shu tur bo'lsin | : |
| Keyin maydon qo'shiladi | : |
| Aniq kalitlar saqlansin | satisfies |
Sozlama obyektlari, marshrutlar jadvali, rang palitrasi -
bularning hammasi uchun satisfies to'g'riroq: siz ham
tekshiruvni olasiz, ham aniq bilimni yo'qotmaysiz.
enum #
enum Daraja {
Past,
Orta,
Yuqori,
}
console.log(Daraja.Orta);
console.log(Daraja[1]);
console.log(Object.keys(Daraja).join(","));
tsx src/enum.ts
1
Orta
0,1,2,Past,Orta,Yuqori
Uchta narsa ko'rindi:
Daraja.Orta-1, chunki raqamlar noldan boshlab beriladi;Daraja[1]-"Orta", ya'ni teskari moslik bor;- kalitlar soni uchta emas, oltita.
Chunki enum ish vaqtida haqiqiy obyektga aylanadi:
export enum Daraja {
Past,
Orta,
}
tsc
echo "--- dist/enum2.js ---"
cat dist/enum2.js
--- dist/enum2.js ---
export var Daraja;
(function (Daraja) {
Daraja[Daraja["Past"] = 0] = "Past";
Daraja[Daraja["Orta"] = 1] = "Orta";
})(Daraja || (Daraja = {}));
Har bir a'zo ikki marta yoziladi - nomdan raqamga va raqamdan nomga.
Satrli enum da teskari moslik yo'q:
enum Usul {
Naqd = "naqd",
Karta = "karta",
}
console.log(Usul.Naqd);
console.log(Object.keys(Usul).join(","));
tsx src/enum3.ts
naqd
Naqd,Karta
enum ning ikki qirrasi #
Raqamli enum ilgari istalgan sonni qabul qilardi. Bu
zamonaviy TypeScript da tuzatilgan:
enum Daraja {
Past,
Orta,
Yuqori,
}
const a: Daraja = 99;
const b: Daraja = Daraja.Past;
console.log(a, b);
tsc --noEmit 2>&1 | fold -sw 74
src/enum4.ts(7,7): error TS2322: Type '99' is not assignable to type
'Daraja'.
Satrli enum esa nominal - qiymati bir xil bo'lsa ham,
oddiy satr unga mos kelmaydi:
enum Usul {
Naqd = "naqd",
Karta = "karta",
}
function chop(u: Usul): string {
return u;
}
console.log(chop(Usul.Naqd));
chop("naqd");
tsc --noEmit 2>&1 | fold -sw 74
src/enum5.ts(11,6): error TS2345: Argument of type '"naqd"' is not
assignable to parameter of type 'Usul'.
Bu - butun tur tizimidagi ikkinchi nominal joy (birinchisi -
10-bobdagi private maydonli sinflar).
Amalda bu noqulay: serverdan "naqd" kelganda uni Usul.Naqd
ga aylantirishga to'g'ri keladi.
const enum #
const enum Yonalish {
Yuqori = 1,
Past,
}
export const y = Yonalish.Yuqori;
console.log(y, Yonalish.Past);
tsc
echo "--- dist/cenum.js ---"
cat dist/cenum.js
echo "--- isolatedModules bilan ---"
tsc --noEmit --isolatedModules 2>&1 | fold -sw 74
--- dist/cenum.js ---
export const y = 1 /* Yonalish.Yuqori */;
console.log(y, 2 /* Yonalish.Past */);
--- isolatedModules bilan ---
const enum hech qanday obyekt qoldirmadi - qiymatlar
o'rniga to'g'ridan-to'g'ri 1 va 2 yozildi. tsc esa
--isolatedModules bilan ham hech narsa demadi.
const enum dan voz kechingYuqoridagi jimlik xavfsizlikni anglatmaydi.
Inlaytirish uchun kompilyator enum ning qiymatlarini
bilishi kerak. esbuild, swc va Babel esa har bir faylni
alohida o'giradi - ular qo'shni fayldagi const enum ni
ko'rmaydi.
Natijada:
- Vite yoki esbuild ishlatilsa, boshqa fayldan import
qilingan
const enumto'g'ri ishlamaydi; - e'lon fayli (
.d.ts) tarqatadigan kutubxonada u butunlay ishlatib bo'lmaydi.
Shuning uchun TypeScript hujjati ham, ko'p uslub
qo'llanmalari ham const enum ni tavsiya qilmaydi.
enum o'rniga literal union #
const USULLAR = ["naqd", "karta"] as const;
type Usul = (typeof USULLAR)[number];
function chop(u: Usul): string {
return "usul: " + u;
}
console.log(chop("naqd"));
for (const u of USULLAR) console.log(chop(u));
tsx src/union.ts
usul: naqd
usul: naqd
usul: karta
chop("naqd") to'g'ridan-to'g'ri ishladi - hech qanday
aylantirish kerak bo'lmadi.
enum Usul | as const + union | |
|---|---|---|
| Ish vaqtidagi kod | Bor | Yo'q |
| Satr bilan mos | Yo'q | Ha |
| Ro'yxat bo'ylab aylanish | Object.values | To'g'ridan-to'g'ri |
| JSON bilan ishlash | Aylantirish kerak | To'g'ridan-to'g'ri |
| Teskari moslik | Bor | Yo'q |
Teskari moslik chindan kerak bo'lgan kam sonli holatlardan tashqari, ikkinchi ustun deyarli har doim afzal.
Shablon literal turlari #
type Rang = "qizil" | "yashil";
type Olcham = "kichik" | "katta";
type Sinf = `${Rang}-${Olcham}`;
const a: Sinf = "qizil-katta";
const b: Sinf = "yashil-kichik";
console.log(a, b);
tsx src/shablon.ts
qizil-katta yashil-kichik
type Rang = "qizil" | "yashil";
type Olcham = "kichik" | "katta";
type Sinf = `${Rang}-${Olcham}`;
const x: Sinf = "qizil-orta";
tsc --noEmit 2>&1 | fold -sw 74
src/shablon2.ts(5,7): error TS2322: Type '"qizil-orta"' is not assignable
to type '"qizil-kichik" | "qizil-katta" | "yashil-kichik" |
"yashil-katta"'.
Xato xabari eng qiziq qismini ko'rsatdi: TypeScript ikkita ikki a'zoli uniondan to'rtta birikma yasadi.
13-bobdagi Capitalize bilan birga:
type Hodisa = "bosildi" | "yopildi";
type Ishlovchi = `on${Capitalize<Hodisa>}`;
const ishlovchilar: Record<Ishlovchi, () => void> = {
onBosildi: () => console.log("bosildi"),
onYopildi: () => console.log("yopildi"),
};
ishlovchilar.onBosildi();
ishlovchilar.onYopildi();
tsx src/shablon3.ts
bosildi
yopildi
Shablon literal turi barcha birikmalarni yaratadi. Uchta 10 a'zoli union - bu 1000 ta variant.
TypeScript da bu chegara 100 000 atrofida; undan oshsa
TS2590 xatosi chiqadi va tahrirlovchi sekinlashadi.
Uchtadan ko'p union ni shablonda birlashtirishdan oldin o'ylab ko'ring.
Xulosa #
- Tur kengayishi o'zgaruvchanlikdan kelib chiqadi:
letva obyekt maydonlari kengayadi,constesa yo'q. - Obyekt literalining maydoni
constichida ham kengayadi - chunki maydonni keyin o'zgartirish mumkin. - Uchta yechim: o'zgaruvchiga tur yozish,
"qiymat" as const, yoki butun obyektgaas const. - Annotatsiya (
: Tur) qiymatning turini almashtiradi va aniq kalitlar haqidagi bilimni yo'qotadi. satisfiestekshiradi, lekin turni almashtirmaydi - sozlama obyektlari uchun eng mos tanlov.- Raqamli
enumteskari moslikka ega va kalitlari soni ikki barobar ko'p. enumkompilyatsiyadan keyin ham kod qoldiradi - literal union esa qoldirmaydi.- Satrli
enumnominal:"naqd"qiymatiUsul.Naqdga mos kelmaydi. const enuminlaytiriladi, lekin transpilyatsiya vositalari bilan ishlamaydi - undan voz keching.as constmassiv +(typeof X)[number]-enumning zamonaviy o'rnini bosuvchisi.- Shablon literal turlari union larni ko'paytiradi; ular bilan ehtiyot bo'ling.
constvaletbilan bir xil satr yozib, turlarini solishtiring.- Obyekt literalini ajratuvchi maydonli turga berib, kengayish xatosini oling.
- Uni uch xil usulda tuzating.
Record<string, number>ga annotatsiya bilan qiymat berib, mavjud bo'lmagan kalitni o'qing va dasturni yiqiting.- Xuddi shuni
satisfiesbilan yozib, kompilyatsiyada tutilishini ko'ring. - Raqamli
enumyozib,Object.keysnatijasini sanang. tscchiqishidaenumqanday kodga aylanganini o'qing.- Satrli
enumkutadigan funksiyaga oddiy satr berib,TS2345ni oling. - O'sha
enumnias constunion ga almashtirib, muammo yo'qolishini tasdiqlang. - Ikkita uniondan shablon literal turi yasab, nechta variant hosil bo'lganini xato xabaridan o'qing.
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.