any, unknown, never o'rtasidagi farq nimada?

MiddleTypeScript #typescript

Savol

TypeScript'da any, unknown va never tiplari bir-biridan nimasi bilan farq qiladi?

Qisqa javob

any qiymat uchun tip tekshiruvini butunlay o'chiradi. unknown ham "har qanday qiymat", lekin xavfsiz: undan foydalanishdan oldin uni toraytirish (type narrowing) kerak. never — mavjud bo'lmagan qiymatlar tipi, odatda yetib bo'lmaydigan kodni yoki boshqaruvni hech qachon qaytarmaydigan funksiyani anglatadi.

Batafsil javob

  • any — tip tizimidan "chiqish". any tipidagi o'zgaruvchi bilan kompilyator xatosisiz istalgan narsani qilish mumkin: funksiya sifatida chaqirish, istalgan xususiyatga murojaat qilish, boshqa istalgan tipdagi o'zgaruvchiga tayinlash. Bu qulay, lekin TypeScript'ning ma'nosini yo'qqa chiqaradi — xatolar faqat runtime'da chiqadi.
  • unknown — anyga tip xavfsizligini saqlaydigan alternativa. unknown tipidagi o'zgaruvchiga har qanday narsani yozish mumkin, lekin TypeScript aniq tipga ishonch hosil qilmaguncha uni ishlatib bo'lmaydi — typeof, instanceof, o'ziga xos type guard yoki aniq keltirish (as) orqali. Bu dasturchini barcha mumkin bo'lgan variantlarni aniq qayta ishlashga majbur qiladi.
  • never — birorta ham mumkin bo'lgan qiymati bo'lmagan tip. Quyidagilar uchun ishlatiladi:
    • har doim istisno tashlaydigan yoki cheksiz siklga kiradigan (boshqaruvni qaytarmaydigan) funksiyalar uchun;
    • tiplar birlashmasi bo'yicha switch/ifning to'liq tekshiruvi (exhaustiveness check) natijasi — "bo'lishi mumkin emas" tarmog'ida tip nevergacha toraytiriladi.

Misol

let a: any = 'hello'
a.toFixed() // xatosiz kompilyatsiya qilinadi, runtime'da qulaydi

let u: unknown = 'hello'
u.toUpperCase() // Error: Object is of type 'unknown'
if (typeof u === 'string') {
  u.toUpperCase() // OK — tip string gacha toraytirildi
}

function fail(message: string): never {
  throw new Error(message)
}

type Shape = { kind: 'circle'; r: number } | { kind: 'square'; side: number }

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle': return Math.PI * shape.r ** 2
    case 'square': return shape.side ** 2
    default:
      const exhaustiveCheck: never = shape // agar case unutilsa, kompilyatsiya xatosi
      return exhaustiveCheck
  }
}

Qo'shimcha savollar

  • Nega unknown anyga qaraganda xavfsizroq almashtiruvchi hisoblanadi?
  • never kompilyatsiya bosqichida switchda unutilgan case'ni topishga qanday yordam beradi?
  • O'zgaruvchi haqiqatan ham never tipidagi qiymatga ega bo'lishi mumkinmi?