TypeScript'da qanday tez-tez uchraydigan antipatternlar bor?

MiddleTypeScript #typescript #antipatterns

Savol

TypeScript'da qaysi amaliyotlar antipattern hisoblanadi va nega ular xavfli?

Qisqa javob

Eng ko'p uchraydigan antipatternlar — anydan suiiste'mol qilish (tip tekshiruvini butunlay o'chiradi), as orqali xavfsiz bo'lmagan keltirishlar, non-null assertion'dan (!) suiiste'mol qilish, xatolarni tuzatish o'rniga @ts-ignore orqali bostirish va sonli enumlarning nozik tuzoqlari. Ularning barchasi "xatoni hozir topish" muvozanatini "xatoni prodakshnda topish"ga o'zgartiradi.

Batafsil javob

1. anydan suiiste'mol qilish. any qiymat uchun va undan keyin chiqarilgan hamma narsa uchun tip tekshiruvini butunlay o'chiradi — aslida oddiy JavaScript'ga qaytish, lekin xavfsizlik haqida yolg'on tuyg'u bilan:

function process(data: any) {
  return data.user.profile.name.toUpperCase() // birorta ham xato tutilmaydi
}

To'g'ri alternativa — unknown (ishlatishdan oldin aniq toraytirishni talab qiladi) yoki aniq tip/generic.

2. Xavfsiz bo'lmagan as-keltirishlar. as tiplarning mosligini runtime darajasida tekshirmaydi — bu shunchaki kompilyatorga "dasturchiga ishonish" haqida "bayonot". unknown/tekshirilmagan ma'lumotlardan as obyektning noto'g'ri shaklini yashirib qo'yishi mumkin:

const response = await fetch('/api/user')
const user = (await response.json()) as User // TS ishonadi, lekin struktura tekshirilmagan
console.log(user.email.toLowerCase()) // email bo'lmasa runtime'da qulaydi

Xavfsizroq yo'l — ma'lumotlarni validatsiya qilish (qo'lda type guard orqali yoki zod kabi kutubxona bilan) "ko'r-ko'rona" keltirish o'rniga.

3. Har ehtimolga qarshi non-null assertion (!). ! operatori kompilyatorga "bu yerda aniq null/undefined emas" deb aytadi, tekshiruvni o'chiradi — agar dasturchi xato qilgan bo'lsa, Cannot read properties of undefined runtime xatosi chiqadi:

function getUser(id: number): User | undefined { /* ... */ return undefined }

const user = getUser(1)!  // "undefined emasligiga ishonchim komil" — agar unday bo'lmasa-chi?
console.log(user.name)     // runtime'da qulaydi

Yaxshisi — haqiqiy tekshiruv (if (!user) return) yoki mavjud bo'lmagan qiymatni aniq qayta ishlash.

4. Tiplarni tuzatish o'rniga @ts-ignore / @ts-expect-error. @ts-ignore keyingi qatordagi kompilyator xatosini sababini tushuntirmasdan va xato umuman hali ham mavjudligini tekshirmasdan bostiradi — vaqt o'tishi bilan atrofdagi kod o'zgarishi mumkin, e'tiborsiz qoldirilgan xato esa boshqa, sezilmagan xatoga aylanishi mumkin:

// @ts-ignore
const result = riskyFunction(wrongArgType) // nega bu normal? noma'lum

@ts-expect-error biroz xavfsizroq — agar quyidagi kod xato bo'lmay qolsa (ya'ni muammo yo'qolsa), o'zining xatosini chiqaradi, lekin ikkala direktivani ham "build'ni o'tkazish usuli" sifatida emas, balki nuqtali va izoh bilan ishlatish kerak.

5. Sonli enumlarning tuzoqlari. Sonli enum ikki tomonlama mapping'ga (qiymat → nom va nom → qiymat) kompilyatsiya qilinadi va bu tipdagi o'zgaruvchiga istalgan sonni xatosiz tayinlashga ruxsat beradi:

enum Status { Pending, Success, Error }

let s: Status = 99 // Sonli enum uchun OK! Diapazon tekshiruvi umuman yo'q

Satrli enumlar bu jihatdan xavfsizroq, lekin ko'pincha satr literallari birlashmasiga (type Status = 'pending' | 'success' | 'error') ustunlik beriladi — ular runtime'da qo'shimcha JS kodi generatsiya qilmaydi va strukturaviy tiplash bilan yaxshiroq mos keladi.

Misol

// Yomon: any, as va ! birgalikda
function renderBad(input: any) {
  const user = input as { name: string }
  return user!.name.toUpperCase()
}

// Yaxshi: unknown + type guard + ma'lumot yo'qligini aniq qayta ishlash
interface User { name: string }

function isUser(value: unknown): value is User {
  return typeof value === 'object' && value !== null && 'name' in value
    && typeof (value as User).name === 'string'
}

function renderGood(input: unknown): string {
  if (!isUser(input)) {
    throw new Error('Invalid user payload')
  }
  return input.name.toUpperCase() // input as va ! siz User'gacha toraytirilgan
}

// Yomon: ixtiyoriy sonlardan himoyasiz sonli enum
enum RoleBad { Admin, User, Guest }

// Yaxshi: literallar birlashmasi — xuddi shu ifodalilik, runtime kodisiz va teshiksiz
type Role = 'admin' | 'user' | 'guest'

function checkAccess(role: Role) {
  if (role === 'admin') return true
  return false
}

Qo'shimcha savollar

  • unknown xavfsizlik nuqtai nazaridan anydan tubdan nimasi bilan farq qiladi?
  • Qanday kam uchraydigan holatlarda as haqiqatan ham o'zini oqlaydi va antipattern hisoblanmaydi?
  • Nega satrli enumlar ham satr literallari birlashmasiga nisbatan ideal emas va enum qachon baribir o'rinli bo'ladi?