Union tiplar Intersection tiplardan nimasi bilan farq qiladi?

MiddleTypeScript #typescript #union #intersection

Savol

Union tiplar (A | B) bilan intersection tiplar (A & B) o'rtasidagi farq nimada?

Qisqa javob

Union (|) "sanab o'tilgan tiplardan biriga tegishli qiymat" degani — tip toraytirilmaguncha faqat barcha variantlarga umumiy bo'lgan xususiyatlar mavjud bo'ladi. Intersection (&) "sanab o'tilgan barcha tiplarni bir vaqtda qanoatlantiradigan qiymat" degani — ularning xususiyatlarini bitta obyektda birlashtiradi.

Batafsil javob

Union tip bir nechta tiplardan biri bo'lishi mumkin bo'lgan qiymatni tasvirlaydi. Union bilan to'g'ridan-to'g'ri faqat barcha variantlarga umumiy bo'lgan narsalar bilan ishlash mumkin (imkoniyatlarning kesishmasi) — muayyan maydonlarga kirish uchun avval tipni toraytirish (type narrowing) kerak:

type Id = string | number

function printId(id: Id) {
  console.log(id.toString()) // OK — toString ham string, ham number'da bor
  // id.toUpperCase() // Xato — faqat string'da bor
}

Intersection tip bir nechta tipni bitta tipga birlashtiradi, unda ularning barchasining maydonlari mavjud bo'ladi. Agar tiplar obyekt tiplari bo'lsa, qiymat ikkalasiga bir vaqtda mos kelishi kerak:

interface Timestamped { createdAt: Date }
interface Named { name: string }

type NamedEntity = Timestamped & Named
// obyekt HAM createdAt, HAM name'ga ega bo'lishi shart

const entity: NamedEntity = { createdAt: new Date(), name: 'Item 1' }

Muhim nuqta: agar mos kelmaydigan primitiv tiplar kesishsa, natija — never, chunki bir vaqtning o'zida ham string, ham number bo'lgan qiymat mavjud emas:

type Impossible = string & number // never

Nomi bir xil, lekin qiymat tipi har xil bo'lgan xususiyatga ega obyekt tiplari uchun ham intersection'dagi xususiyat neverga qulab tushadi:

type A = { value: string }
type B = { value: number }
type C = A & B // { value: never }

Amaliyotda tez-tez uchraydigan pattern — discriminated union (umumiy diskriminator-maydonli birlashma), u union'ning qulayligini (variantlar moslashuvchanligi) diskriminator-belgi maydoni bo'yicha switch/if orqali xavfsiz toraytirish imkoniyati bilan birlashtiradi.

Misol

// Union: so'rov natijasi — ikki variantdan biri
type RequestState<T> =
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; message: string }

function render(state: RequestState<string[]>) {
  switch (state.status) {
    case 'loading': return 'Yuklanmoqda...'
    case 'success': return state.data.join(', ') // data faqat shu yerda mavjud
    case 'error': return `Xato: ${state.message}`
  }
}

// Intersection: tugmaning bazaviy propslarini muayyan variant propslari bilan birlashtiramiz
interface BaseButtonProps { onClick: () => void; disabled?: boolean }
interface IconButtonProps { icon: string; 'aria-label': string }

type IconButton = BaseButtonProps & IconButtonProps

const btn: IconButton = {
  onClick: () => console.log('clicked'),
  icon: 'trash',
  'aria-label': "O'chirish",
}

Qo'shimcha savollar

  • Discriminated union nima va nega u uchun yagona literal diskriminator-maydon muhim?
  • TypeScript ikkita har xil signaturali funksional tiplarning kesishmasini (&) qanday qayta ishlaydi?
  • Obyektlarning union tipi bilan intersection tipi o'rtasida ruxsat etilgan qiymatlar to'plami nuqtai nazaridan qanday farq bor?