O'zbek

Strukturaviy tip tizimida nominal tipizatsiyaga erishishning kuchli usuli bo'lgan TypeScript branded types'ni o'rganing. Tip xavfsizligi va kodning tushunarliligini qanday oshirishni bilib oling.

TypeScript Branded Types: Strukturaviy Tizimda Nominal Tipizatsiya

TypeScript'ning strukturaviy tip tizimi moslashuvchanlikni ta'minlaydi, ammo ba'zan kutilmagan xatti-harakatlarga olib kelishi mumkin. Branded types nominal tipizatsiyani qo'llash imkonini berib, tip xavfsizligi va kodning tushunarliligini oshiradi. Ushbu maqolada branded types batafsil ko'rib chiqiladi, ularni amalga oshirish uchun amaliy misollar va eng yaxshi amaliyotlar taqdim etiladi.

Strukturaviy va Nominal Tipizatsiyani Tushunish

Branded types'ni o'rganishdan oldin, keling, strukturaviy va nominal tipizatsiya o'rtasidagi farqni aniqlashtirib olaylik.

Strukturaviy Tipizatsiya (Duck Typing)

Strukturaviy tip tizimida, agar ikkita tip bir xil strukturaga ega bo'lsa (ya'ni, bir xil tiplarga ega bo'lgan bir xil xususiyatlarga ega bo'lsa), ular mos keluvchi hisoblanadi. TypeScript strukturaviy tipizatsiyadan foydalanadi. Quyidagi misolni ko'rib chiqing:


interface Point {
  x: number;
  y: number;
}

interface Vector {
  x: number;
  y: number;
}

const point: Point = { x: 10, y: 20 };
const vector: Vector = point; // Valid in TypeScript

console.log(vector.x); // Output: 10

Garchi Point va Vector alohida tiplar sifatida e'lon qilingan bo'lsa-da, TypeScript Point obyektini Vector o'zgaruvchisiga tayinlashga ruxsat beradi, chunki ular bir xil strukturaga ega. Bu qulay bo'lishi mumkin, ammo agar siz bir xil shaklga ega bo'lgan mantiqiy jihatdan farq qiluvchi tiplarni ajratishingiz kerak bo'lsa, bu xatoliklarga olib kelishi mumkin. Masalan, tasodifan ekran piksel koordinatalariga mos kelishi mumkin bo'lgan kenglik/uzunlik koordinatalari haqida o'ylash.

Nominal Tipizatsiya

Nominal tip tizimida tiplar faqat bir xil nomga ega bo'lsagina mos keluvchi hisoblanadi. Agar ikkita tip bir xil strukturaga ega bo'lsa ham, ularning nomlari har xil bo'lsa, ular alohida hisoblanadi. Java va C# kabi tillar nominal tipizatsiyadan foydalanadi.

Branded Types'ga bo'lgan Ehtiyoj

TypeScript'ning strukturaviy tipizatsiyasi qiymatning strukturasidan qat'i nazar, ma'lum bir tipga tegishli ekanligini ta'minlash kerak bo'lganda muammoli bo'lishi mumkin. Masalan, valyutalarni ifodalashni ko'rib chiqing. Sizda USD va EUR uchun turli tiplar bo'lishi mumkin, ammo ularning ikkalasi ham raqamlar sifatida ifodalanishi mumkin. Ularni farqlash mexanizmisiz, siz tasodifan noto'g'ri valyuta ustida amallarni bajarib qo'yishingiz mumkin.

Branded types bu muammoni hal qiladi, chunki ular strukturaviy jihatdan o'xshash, ammo tip tizimi tomonidan farqli deb hisoblanadigan alohida tiplarni yaratishga imkon beradi. Bu tip xavfsizligini oshiradi va aks holda o'tib ketishi mumkin bo'lgan xatoliklarning oldini oladi.

TypeScript'da Branded Types'ni Amalga Oshirish

Branded types kesishma tiplar (intersection types) va noyob simvol yoki string literal yordamida amalga oshiriladi. G'oya shundan iboratki, tipga uni bir xil strukturaga ega bo'lgan boshqa tiplardan ajratib turadigan "brend" qo'shiladi.

Simvollardan Foydalanish (Tavsiya Etiladi)

Brendlash uchun simvollardan foydalanish odatda afzalroqdir, chunki simvollar noyob bo'lishi kafolatlangan.


const USD = Symbol('USD');
type USD = number & { readonly [USD]: unique symbol };

const EUR = Symbol('EUR');
type EUR = number & { readonly [EUR]: unique symbol };

function createUSD(value: number): USD {
  return value as USD;
}

function createEUR(value: number): EUR {
  return value as EUR;
}

function addUSD(a: USD, b: USD): USD {
  return (a + b) as USD;
}

const usd1 = createUSD(10);
const usd2 = createUSD(20);
const eur1 = createEUR(15);

const totalUSD = addUSD(usd1, usd2);
console.log("Total USD:", totalUSD);

// Uncommenting the next line will cause a type error
// const invalidOperation = addUSD(usd1, eur1);

Ushbu misolda, USD va EUR number tipiga asoslangan branded tiplardir. unique symbol bu tiplarning alohida ekanligini ta'minlaydi. createUSD va createEUR funksiyalari bu tiplarning qiymatlarini yaratish uchun ishlatiladi va addUSD funksiyasi faqat USD qiymatlarini qabul qiladi. EUR qiymatini USD qiymatiga qo'shishga urinish tip xatoligiga olib keladi.

String Literallaridan Foydalanish

Siz brendlash uchun string literallaridan ham foydalanishingiz mumkin, garchi bu yondashuv simvollardan foydalanishga qaraganda kamroq ishonchli bo'lsa-da, chunki string literallari noyob bo'lishi kafolatlanmagan.


type USD = number & { readonly __brand: 'USD' };
type EUR = number & { readonly __brand: 'EUR' };

function createUSD(value: number): USD {
  return value as USD;
}

function createEUR(value: number): EUR {
  return value as EUR;
}

function addUSD(a: USD, b: USD): USD {
  return (a + b) as USD;
}

const usd1 = createUSD(10);
const usd2 = createUSD(20);
const eur1 = createEUR(15);

const totalUSD = addUSD(usd1, usd2);
console.log("Total USD:", totalUSD);

// Uncommenting the next line will cause a type error
// const invalidOperation = addUSD(usd1, eur1);

Bu misol avvalgisiga o'xshash natijaga erishadi, lekin simvollar o'rniga string literallaridan foydalanadi. Bu soddaroq bo'lsa-da, brendlash uchun ishlatiladigan string literallarining kod bazangizda noyob ekanligiga ishonch hosil qilish muhimdir.

Amaliy Misollar va Qo'llash Holatlari

Branded types strukturaviy moslikdan tashqari tip xavfsizligini ta'minlash kerak bo'lgan turli xil stsenariylarda qo'llanilishi mumkin.

ID'lar

UserID, ProductID va OrderID kabi turli xil ID'larga ega tizimni ko'rib chiqing. Bu ID'larning barchasi raqamlar yoki satrlar sifatida ifodalanishi mumkin, ammo siz turli xil ID tiplarini tasodifan aralashtirib yuborishning oldini olishni xohlaysiz.


const UserIDBrand = Symbol('UserID');
type UserID = string & { readonly [UserIDBrand]: unique symbol };

const ProductIDBrand = Symbol('ProductID');
type ProductID = string & { readonly [ProductIDBrand]: unique symbol };

function getUser(id: UserID): { name: string } {
  // ... fetch user data
  return { name: "Alice" };
}

function getProduct(id: ProductID): { name: string, price: number } {
  // ... fetch product data
  return { name: "Example Product", price: 25 };
}

function createUserID(id: string): UserID {
  return id as UserID;
}

function createProductID(id: string): ProductID {
  return id as ProductID;
}

const userID = createUserID('user123');
const productID = createProductID('product456');

const user = getUser(userID);
const product = getProduct(productID);

console.log("User:", user);
console.log("Product:", product);

// Uncommenting the next line will cause a type error
// const invalidCall = getUser(productID);

Ushbu misol, branded tiplar ProductID'ni UserID'ni kutayotgan funksiyaga o'tkazishning oldini olib, tip xavfsizligini qanday oshirishini ko'rsatadi.

Domen-Maxsus Qiymatlar

Branded types, shuningdek, cheklovlarga ega bo'lgan domen-maxsus qiymatlarni ifodalash uchun ham foydali bo'lishi mumkin. Masalan, sizda har doim 0 dan 100 gacha bo'lishi kerak bo'lgan foizlar uchun tip bo'lishi mumkin.


const PercentageBrand = Symbol('Percentage');
type Percentage = number & { readonly [PercentageBrand]: unique symbol };

function createPercentage(value: number): Percentage {
  if (value < 0 || value > 100) {
    throw new Error('Percentage must be between 0 and 100');
  }
  return value as Percentage;
}

function applyDiscount(price: number, discount: Percentage): number {
  return price * (1 - discount / 100);
}

try {
  const discount = createPercentage(20);
  const discountedPrice = applyDiscount(100, discount);
  console.log("Discounted Price:", discountedPrice);

  // Uncommenting the next line will cause an error during runtime
  // const invalidPercentage = createPercentage(120);
} catch (error) {
  console.error(error);
}

Ushbu misol, ish vaqtida (runtime) branded tip qiymatiga cheklovni qanday qo'llashni ko'rsatadi. Tip tizimi Percentage qiymatining har doim 0 dan 100 gacha ekanligini kafolatlay olmasa-da, createPercentage funksiyasi bu cheklovni ish vaqtida amalga oshirishi mumkin. Shuningdek, siz io-ts kabi kutubxonalardan foydalanib, branded tiplarning ish vaqtidagi validatsiyasini amalga oshirishingiz mumkin.

Sana va Vaqt Ko'rinishlari

Sanalar va vaqtlar bilan ishlash turli formatlar va vaqt zonalari tufayli murakkab bo'lishi mumkin. Branded types turli sana va vaqt ko'rinishlarini farqlashga yordam beradi.


const UTCDateBrand = Symbol('UTCDate');
type UTCDate = string & { readonly [UTCDateBrand]: unique symbol };

const LocalDateBrand = Symbol('LocalDate');
type LocalDate = string & { readonly [LocalDateBrand]: unique symbol };

function createUTCDate(dateString: string): UTCDate {
  // Validate that the date string is in UTC format (e.g., ISO 8601 with Z)
  if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(dateString)) {
    throw new Error('Invalid UTC date format');
  }
  return dateString as UTCDate;
}

function createLocalDate(dateString: string): LocalDate {
  // Validate that the date string is in local date format (e.g., YYYY-MM-DD)
  if (!/\d{4}-\d{2}-\d{2}/.test(dateString)) {
    throw new Error('Invalid local date format');
  }
  return dateString as LocalDate;
}

function convertUTCDateToLocalDate(utcDate: UTCDate): LocalDate {
  // Perform time zone conversion
  const date = new Date(utcDate);
  const localDateString = date.toLocaleDateString();
  return createLocalDate(localDateString);
}

try {
  const utcDate = createUTCDate('2024-01-20T10:00:00.000Z');
  const localDate = convertUTCDateToLocalDate(utcDate);
  console.log("UTC Date:", utcDate);
  console.log("Local Date:", localDate);
} catch (error) {
  console.error(error);
}

Ushbu misol UTC va mahalliy sanalarni farqlab, ilovangizning turli qismlarida to'g'ri sana va vaqt ko'rinishi bilan ishlayotganingizni ta'minlaydi. Ish vaqtidagi validatsiya faqat to'g'ri formatlangan sana satrlari bu tiplarga tayinlanishi mumkinligini ta'minlaydi.

Branded Types'dan Foydalanish bo'yicha Eng Yaxshi Amaliyotlar

TypeScript'da branded tiplardan samarali foydalanish uchun quyidagi eng yaxshi amaliyotlarni ko'rib chiqing:

Branded Types'ning Afzalliklari

Branded Types'ning Kamchiliklari

Branded Types'ga Alternativalar

Branded tiplar TypeScript'da nominal tipizatsiyaga erishishning kuchli usuli bo'lsa-da, siz ko'rib chiqishingiz mumkin bo'lgan muqobil yondashuvlar ham mavjud.

Shaffof bo'lmagan Tiplar (Opaque Types)

Shaffof bo'lmagan tiplar (Opaque types) branded tiplarga o'xshaydi, ammo asosiy tipni yashirishning yanada aniqroq usulini ta'minlaydi. TypeScript'da shaffof bo'lmagan tiplar uchun o'rnatilgan yordam mavjud emas, lekin siz ularni modullar va xususiy simvollar yordamida simulyatsiya qilishingiz mumkin.

Klasslar

Klasslardan foydalanish alohida tiplarni aniqlash uchun yanada obyektga yo'naltirilgan yondashuvni ta'minlashi mumkin. TypeScript'da klasslar strukturaviy jihatdan tiplashtirilgan bo'lsa-da, ular vazifalarni aniqroq ajratishni taklif qiladi va metodlar orqali cheklovlarni amalga oshirish uchun ishlatilishi mumkin.

io-ts yoki zod kabi kutubxonalar

Ushbu kutubxonalar murakkab ish vaqti tip validatsiyasini ta'minlaydi va kompilyatsiya vaqti va ish vaqti xavfsizligini ta'minlash uchun branded tiplar bilan birgalikda ishlatilishi mumkin.

Xulosa

TypeScript branded tiplari strukturaviy tip tizimida tip xavfsizligi va kodning tushunarliligini oshirish uchun qimmatli vositadir. Tipga "brend" qo'shish orqali siz nominal tipizatsiyani amalga oshirishingiz va strukturaviy jihatdan o'xshash, ammo mantiqiy jihatdan farq qiluvchi tiplarning tasodifiy aralashib ketishining oldini olishingiz mumkin. Branded tiplar biroz murakkablik va qo'shimcha yuk olib kelsa-da, yaxshilangan tip xavfsizligi va kodning saqlanuvchanligining afzalliklari ko'pincha kamchiliklardan ustun turadi. Qiymatning strukturasidan qat'i nazar, ma'lum bir tipga tegishli ekanligiga ishonch hosil qilishingiz kerak bo'lgan stsenariylarda branded tiplardan foydalanishni ko'rib chiqing.

Strukturaviy va nominal tipizatsiya ortidagi tamoyillarni tushunib, ushbu maqolada keltirilgan eng yaxshi amaliyotlarni qo'llash orqali siz yanada mustahkam va saqlanuvchan TypeScript kodini yozish uchun branded tiplardan samarali foydalanishingiz mumkin. Valyutalar va ID'larni ifodalashdan tortib, domen-maxsus cheklovlarni amalga oshirishgacha, branded tiplar loyihalaringizda tip xavfsizligini oshirish uchun moslashuvchan va kuchli mexanizmni ta'minlaydi.

TypeScript bilan ishlash jarayonida tipni tekshirish va amalga oshirish uchun mavjud bo'lgan turli usullar va kutubxonalarni o'rganing. Tip xavfsizligiga keng qamrovli yondashuvga erishish uchun branded tiplarni io-ts yoki zod kabi ish vaqti validatsiya kutubxonalari bilan birgalikda ishlatishni ko'rib chiqing.