TypeScript'da klasslar va OOP'ni qanday tiplash kerak?
Savol
Kirish modifikatorlari (public/private/protected), abstrakt klasslar qanday ishlaydi va implements bilan extends o'rtasidagi farq nimada?
Qisqa javob
public (standart bo'yicha), private va protected klass a'zolarining ko'rinishini boshqaradi: private — faqat klass ichida, protected — klass ichida va merosxo'rlarda, public — hamma joyda. abstract class — to'g'ridan-to'g'ri instansiya qilib bo'lmaydigan, merosxo'rlar uchun kontrakt belgilaydigan klass. extends — bitta klassdan amalga oshirishni meros qilib olish, implements — kod merosxo'rligisiz interfeys strukturasini amalga oshirish majburiyati.
Batafsil javob
Kirish modifikatorlari — faqat kompilyatsiya bosqichidagi tekshiruv; kompilyatsiya qilingan JS'da ular runtime'da kirishni hech qanday cheklamaydi (runtime'da ham maxfiylikni ta'minlaydigan haqiqiy private maydonlar #fielddan farqli o'laroq):
class BankAccount {
private balance: number
protected owner: string
public readonly accountId: string
constructor(owner: string, initial: number) {
this.owner = owner
this.balance = initial
this.accountId = crypto.randomUUID()
}
private validate(amount: number) {
if (amount <= 0) throw new Error('Invalid amount')
}
deposit(amount: number) {
this.validate(amount) // OK — klass ichida kirish mumkin
this.balance += amount
}
}
const acc = new BankAccount('Alice', 100)
// acc.balance // Xato — private tashqaridan mavjud emas
// acc.validate(10) // Xato — private metod
Shuningdek qisqartirilgan sintaksis ham bor — parameter properties, u maydonni to'g'ridan-to'g'ri konstruktorda e'lon qiladi va tiplaydi:
class Point {
constructor(public x: number, public y: number) {}
}
// x, y maydonlarini e'lon qilish va ularni konstruktor tanasida tayinlashga ekvivalent
abstract class — new orqali to'g'ridan-to'g'ri yaratib bo'lmaydigan bazaviy klass. U ham amalga oshirilgan metodlarni, ham merosxo'rlarda amalga oshirilishi majburiy bo'lgan tanasiz abstract-metodlarni o'z ichiga olishi mumkin:
abstract class Shape {
abstract area(): number // amalga oshirilmagan — kontrakt
describe(): string { // amalga oshirilgan — barcha merosxo'rlar uchun umumiy
return `Area: ${this.area()}`
}
}
class Circle extends Shape {
constructor(private radius: number) { super() }
area(): number { return Math.PI * this.radius ** 2 }
}
// const s = new Shape() // Xato — abstract klassni instansiya qilib bo'lmaydi
extends vs implements:
extends— klassdan (yoki interfeyslar uchun interfeysdan) meros olish. Merosxo'r ota-klassning amalga oshirilishini (maydonlar, metodlar) oladi va uni qayta aniqlashi mumkin, agar ota-klass konstruktorga ega bo'lsa, konstruktordasuper()ni chaqirishi shart.implements— klass interfeys strukturasiga (yoki vergul orqali bir nechtasiga) mos kelishga majbur bo'ladi, lekin undan hech qanday kod olmaydi — amalga oshirishni to'liq o'zi yozishi kerak. Bu sof kontraktni kompilyatsiya bosqichida tekshirish.
interface Flyable { fly(): void }
interface Swimmable { swim(): void }
class Duck extends Animal implements Flyable, Swimmable {
fly() { console.log('Flying') }
swim() { console.log('Swimming') }
}
Klass bir nechta interfeysni amalga oshirishi mumkin (implements A, B), lekin faqat bitta klassdan meros olishi mumkin (extends — yagona merosxo'rlik).
Misol
abstract class Repository<T extends { id: number }> {
protected items: T[] = []
abstract validate(item: T): boolean
add(item: T): void {
if (!this.validate(item)) throw new Error('Invalid item')
this.items.push(item)
}
findById(id: number): T | undefined {
return this.items.find((i) => i.id === id)
}
}
interface Serializable {
toJSON(): string
}
interface Product { id: number; name: string; price: number }
class ProductRepository extends Repository<Product> implements Serializable {
validate(item: Product): boolean {
return item.price >= 0 && item.name.length > 0
}
toJSON(): string {
return JSON.stringify(this.items)
}
}
const repo = new ProductRepository()
repo.add({ id: 1, name: 'Book', price: 19.99 })
console.log(repo.toJSON())
Qo'shimcha savollar
- Klassning haqiqiy private maydonlari (
#field)privatemodifikatoridan nimasi bilan farq qiladi? - Abstrakt klassda
abstractxususiyatni (metod emas) e'lon qilish mumkinmi? - TypeScript strukturaviy tiplashda klasslarning mosligini qanday tekshiradi —
privatemaydonlar ikkita har xil klassning mosligiga ta'sir qiladimi?