Mundarija (38)
- Bu darsda
- 1. Nega bu kerak?
- 2. Maydonlarni e'lon qilish
- 2.1 Har maydon — e'lon bilan
- 2.2 Maydon albatta qiymat olsin
- 2.3 JSDoc .ts da ishlamaydi
- 3. Kirish modifikatorlari: public, private, protected
- 3.1 Uchta daraja
- 3.2 private va # — farqi nimada?
- 4. readonly: faqat konstruktorda yoziladi
- 4.1 O'zgarmas maydon
- 4.2 Tuzoq: readonly sayoz
- 5. Parameter properties — va nega kanonda yo'q
- 5.1 Qisqa yozuv
- 5.2 Bu sintaksis JavaScript'ga kod qo'shadi
- 5.3 erasableSyntaxOnly: xatoni oldindan ko'rish
- 6. implements: klass va interfeys shartnomasi
- 6.1 Klass va'dani bajaradimi?
- 6.2 Tuzoq: implements turlarni bermaydi
- 7. abstract klass: chala qolip
- 7.1 O'zidan obyekt yasab bo'lmaydi
- 7.2 abstract va interface — qachon qaysi?
- 8. override: "men otaning metodini almashtiryapman"
- 9. Ko'p uchraydigan xatolar
- 9.1 Maydonni e'lon qilmasdan this.x = …
- 9.2 Maydon qiymatsiz qoldi
- 9.3 private ni xavfsizlik deb o'ylash
- 9.4 erasableSyntaxOnly loyihasida parameter properties
- 9.5 implements dan tur kutish
- 9.6 .ts faylda JSDoc tur
- 10. Mashqlar
- 1-mashq (oson): Qaysi qator xato?
- 2-mashq (o'rta): Kanon uslubiga o'tkazing
- 3-mashq (qiyin): Bildirishnomalar
- 4-mashq: Vazifalar qadami — klass modullari .ts ga
- 11. Real ishda
- Xulosa
- Manbalar
TypeScript klasslari: private, readonly, abstract va implements
Qisqacha: TypeScript klassida har maydon e'lon qilinadi (
id: number;) va unga kirish modifikatori beriladi:public(sukut bo'yicha),private,protected. Ular faqattsctekshiruvida yashaydi — ishlash paytida haqiqiy yopiqlik#da.readonlymaydonni faqat konstruktorda yozishga ruxsat beradi,abstractklass — "chala qolip",implementsesa klass interfeysga mosligini tekshiradi.
Bu darsda
- Klass maydonlarini turlari bilan e'lon qilasiz va
strictPropertyInitializationxabarini tushunasiz. private/protectedva#farqini ayta olasiz: biri tekshiruvda, ikkinchisi ishlash paytida.readonly,static readonlyva parameter properties yozasiz — va negavazifalarda parameter properties yo'qligini bilasiz.abstractklass,implementsvaoverridebilan klasslar ierarxiyasini qurasiz.vazifalardagi uchta klass modulini.tsga ko'chirasiz.
Oldin bilishingiz kerak: Index signature va Record, Meros: extends va super, Private # maydon va metodlar, Getter/setter va static a'zolar.
1. Nega bu kerak?
O'tgan darsda obyektlarni turlar bilan yozdik. Klasslar ham obyekt yasaydi, lekin JavaScript'da ularning maydonlari hech qayerda e'lon qilinmaydi — konstruktorda this.x = … deyilgan joyda paydo bo'ladi.
Sardor buyurtma klassini yozdi:
class Order {
constructor(id) {
this.id = id;
this.items = [];
}
add(dish) {
this.itmes.push(dish);
}
}
const order = new Order(1);
order.add("Osh");Konsolda:
TypeError: Cannot read properties of undefined (reading 'push')itmes — harf almashgan. JavaScript uchun bu boshqa, mavjud bo'lmagan xususiyat, demak undefined. Xato faqat add chaqirilganda chiqadi — balki bir hafta keyin, mehmon buyurtma berayotganda.
Ikkinchi muammo: klassning ichki holati tashqaridan buziladi. Kimdir order.items = null yozib qo'ysa, klass bunga to'sqinlik qilmaydi. TypeScript bu ikkalasini ham hal qiladi: klass maydonlari ro'yxati e'lon qilinadi va kim nimaga tegishi mumkinligi yoziladi.
2. Maydonlarni e'lon qilish
2.1 Har maydon — e'lon bilan
«Nega bu kerak?» bo'limidagi klassni so'zma-so'z .ts ga ko'chiramiz:
class Order {
constructor(id: number) {
this.id = id;
}
}Kompilyator:
TS2339: Property 'id' does not exist on type 'Order'.Tarjimasi: "Order turida id xususiyati yo'q". JavaScript'da this.id = id maydonni yaratardi. TypeScript'da esa klass turi — e'lon qilingan maydonlar ro'yxati. id u yerda yo'q, demak unga yozib ham bo'lmaydi.
Tuzatish — klass tanasida maydonni turi bilan e'lon qilish. Bu Private # maydon darsidagi klass maydonlari (class fields) yozuvi, faqat endi tur bilan:
class Order {
id: number;
items: string[] = [];
constructor(id: number) {
this.id = id;
}
add(dish: string): void {
this.items.push(dish);
}
}
const order = new Order(1);
order.add("Osh");
console.log(order.items); // [ 'Osh' ]items ga boshlang'ich qiymat berildi — tur undan ham chiqarilishi mumkin edi, lekin bo'sh massivga tur yozamiz (Massiv va tuple turlari darsidagi qoida). Endi this.itmes yozib ko'ring:
class Order {
items: string[] = [];
add(dish: string): void {
this.itmes.push(dish);
}
}Kompilyator:
TS2551: Property 'itmes' does not exist on type 'Order'. Did you mean 'items'?"Shunday xususiyat yo'q. items demoqchimidingiz?" — TypeScript yaqin nomni ham taklif qildi. Bir hafta keyin chiqadigan TypeError yozish paytiga ko'chdi.
2.2 Maydon albatta qiymat olsin
strict rejimda yana bir tekshiruv bor — strictPropertyInitialization ("xususiyatlarni qat'iy boshlash"). E'lon qilingan maydon konstruktor tugaguncha qiymat olishi kerak:
class Order {
id: number;
total: number;
constructor(id: number) {
this.id = id;
}
}Kompilyator:
TS2564: Property 'total' has no initializer and is not definitely assigned in the constructor.Tarjimasi: "total xususiyatida boshlang'ich qiymat yo'q va u konstruktorda aniq berilmagan". Aks holda order.total turi number, qiymati esa undefined bo'lardi — null va undefined darsidagi tuzoq. Uch tuzatish bor: boshlang'ich qiymat (total = 0), konstruktorda berish, yoki turni rost yozish (total: number | undefined).
To'rtinchi yo'l ham uchraydi — total!: number. Undov belgisi "men bilaman, u albatta beriladi" degan va'da, non-null assertion kabi. TypeScript bu va'dani tekshirmaydi, shuning uchun uni faqat qiymat boshqa joyda (masalan, kutubxona tomonidan) beriladigan holatlar uchun qoldiring.
2.3 JSDoc .ts da ishlamaydi
vazifalar dagi vazifa.js 12-qismdan beri // @ts-check va JSDoc bilan tekshirilardi. U .ts ga faqat nomi o'zgartirilganda, tsc 53 ta xato topdi. Ulardan biri — VazifaXatosi klassida:
assets/js/vazifa.ts(14,10): error TS2339: Property 'kod' does not exist on type 'VazifaXatosi'.JS faylda /** @type {VazifaXatosiKodi} */ this.kod = … maydonni e'lon qilardi. .ts faylda esa JSDoc'dagi turlar hisobga olinmaydi — tur faqat TypeScript sintaksisidan olinadi. Xuddi shu sababli royxat.ts dagi /** @type {Vazifa[]} */ #vazifalar = []; turini yo'qotdi va never[] ga aylandi. Keyin uning har ishlatilishi Property 'id' does not exist on type 'never' berdi (11 ta). Bu xatolarni «Vazifalar qadami» mashqida tuzatamiz.
Tekshirib ko'ring:
class Guest { name: string; constructor() {} }— qaysi xato chiqadi va eng sodda tuzatish qanday?
Javob
TS2564: Property 'name' has no initializer… — name e'lon qilingan, lekin hech qayerda qiymat olmaydi. Eng sodda tuzatish — konstruktorga parametr qo'shib, this.name = name yozish. Yoki mehmon nomi bo'lmasligi mumkin bo'lsa — name: string | undefined (yoki ixtiyoriy name?: string).
3. Kirish modifikatorlari: public, private, protected
3.1 Uchta daraja
TypeScript har maydon va metod oldiga kirish modifikatori (access modifier) qo'yishga ruxsat beradi — "kim tega oladi":
| Modifikator | Klass ichida | Bola klassda | Tashqarida |
|---|---|---|---|
public (sukut bo'yicha) |
ha | ha | ha |
protected |
ha | ha | yo'q |
private |
ha | yo'q | yo'q |
class Table {
private guests = 0;
protected seats = 4;
}
class VipTable extends Table {
describe(): string {
return `${this.seats} o'rin, ${this.guests} mehmon`;
}
}
const table = new Table();
table.guests = 2;
table.seats = 6;Kompilyator:
TS2341: Property 'guests' is private and only accessible within class 'Table'.
TS2341: Property 'guests' is private and only accessible within class 'Table'.
TS2445: Property 'seats' is protected and only accessible within class 'Table' and its subclasses.TS2341: "guests— private, faqatTableklassi ichida ochiq". Ikki marta: bola klassdagithis.guestsva tashqaridagitable.guests.TS2445: "seats— protected, faqatTableva uning bola klasslari ichida ochiq".VipTableichidathis.seatsmumkin, tashqarida — yo'q.
public ni odatda yozishmaydi — modifikatorsiz a'zo shundoq ham ochiq.
3.2 private va # — farqi nimada?
Private # maydon darsida JavaScript'ning o'z yopiq maydonlarini o'rgangansiz. Ikkalasi o'xshash ko'rinadi, lekin ular butunlay boshqa narsalar:
class Account {
private balance = 0;
#pin = "0000";
deposit(sum: number): void {
this.balance += sum;
}
checkPin(pin: string): boolean {
return pin === this.#pin;
}
}
const account = new Account();
account.deposit(50000);
console.log(account["balance"]); // 50000
console.log(JSON.stringify(account)); // {"balance":50000}
console.log(account.checkPin("1234")); // falsetsc xatosiz o'tkazdi, lekin natijaga qarang:
account["balance"]— kvadrat qavs bilanprivatemaydonni o'qish mumkin. TypeScript buni ataylab teshik sifatida qoldirgan (testlarda ichki holatni ko'rish uchun).JSON.stringifybalanceni chiqardi.tscchiqaradigan JavaScript'daprivateso'zi yo'qoladi va maydon oddiy, ochiq maydon bo'lib qoladi:balance = 0;.#pinesa naJSON.stringifyda, na boshqa joyda ko'rinmaydi.account.#pindeb yozish — sintaksis xatosi, tashqi kod uni hatto o'qiy olmaydi.
Tashqaridan # ga murojaat qilsangiz, tsc ham to'xtatadi — bu xabar boshqacha:
class Account {
#pin = "0000";
}
const account = new Account();
console.log(account.#pin);Kompilyator:
TS18013: Property '#pin' is not accessible outside class 'Account' because it has a private identifier.Tarjimasi: "#pin xususiyati Account klassidan tashqarida ochiq emas, chunki u yopiq identifikatorga ega".
private x |
#x |
|
|---|---|---|
| Kim tekshiradi | faqat tsc |
JavaScript dvigateli |
| Ishlash paytida | oddiy ochiq maydon | haqiqatan yopiq |
obj["x"] bilan |
o'qiladi | imkonsiz |
JSON.stringify da |
chiqadi | chiqmaydi |
Qoida: haqiqiy yopiqlik kerak bo'lsa (parol, ichki holat) — #. Loyihamizda ham shunday: Vazifa ning #matn maydoni 10-qismdan beri #. Eski kodda va kutubxonalarda esa private ko'p uchraydi — u # paydo bo'lishidan (ES2022) ancha oldin bor edi. Yana bir farq: protected ning # da muqobili yo'q. Bola klassga ochiq, tashqariga yopiq a'zo kerak bo'lsa, protected ishlatiladi.
Tekshirib ko'ring: Kutubxona
class Cart { private items: string[] = [] }eksport qiladi. Siz uni JavaScript fayldan ishlatyapsiz.cart.items.push("osh")ishlaydimi?
Javob
Ishlaydi. JavaScript faylda tsc tekshiruvi yo'q, private esa build'da o'chib ketgan — items oddiy ochiq maydon. #items bo'lganda — SyntaxError: tashqaridan # ga murojaat JavaScript'ning o'zida taqiqlangan.
4. readonly: faqat konstruktorda yoziladi
4.1 O'zgarmas maydon
Obyekt turlari va massivlardagi readonly klass maydonlarida ham bor. Bunday maydonga faqat e'londa yoki konstruktorda qiymat beriladi:
class Dish {
static readonly MAX_NAME = 40;
readonly id: number;
constructor(id: number) {
this.id = id;
}
rename(): void {
this.id = 7;
}
}
Dish.MAX_NAME = 100;Kompilyator:
TS2540: Cannot assign to 'id' because it is a read-only property.
TS2540: Cannot assign to 'MAX_NAME' because it is a read-only property.Tarjimasi: "id ga yozib bo'lmaydi, chunki u faqat o'qish uchun". Metod ichida ham — readonly maydon obyekt yaratilgandan keyin o'zgarmaydi. static readonly — klassning o'ziga tegishli doimiy (static a'zolar): vazifalar dagi Vazifa.MAKS_UZUNLIK = 100 aynan shunday.
4.2 Tuzoq: readonly sayoz
readonly faqat maydonni qayta tayinlashni taqiqlaydi, ichidagi massiv yoki obyektni emas:
class Menu {
readonly dishes: string[] = ["Osh"];
}
const menu = new Menu();
menu.dishes.push("Manti");
console.log(menu.dishes); // [ 'Osh', 'Manti' ]tsc — xatosiz. menu.dishes = [] taqiqlangan, lekin push — massivning metodi, maydonga yozish emas. Massiv ham o'zgarmasin desangiz, uning turini ham readonly qiling: readonly dishes: readonly string[]. Unda push ham TS2339 beradi (Massiv va tuple turlari).
5. Parameter properties — va nega kanonda yo'q
5.1 Qisqa yozuv
Maydonni e'lon qilib, keyin konstruktorda tayinlash — takror. TypeScript'da buning qisqa yozuvi bor — parameter properties (parametr xususiyatlari):
class Guest {
constructor(
public readonly name: string,
private phone: string,
) {}
masked(): string {
return `${this.name}: ***${this.phone.slice(-2)}`;
}
}
const guest = new Guest("Malika", "+998 90 000 00 00");
console.log(guest.masked()); // Malika: ***00Konstruktor parametri oldidagi modifikator (public, private, protected, readonly) TypeScript'ga aytadi: "shu nomli maydon yarat va parametrni unga yoz". Tana bo'sh ({}), lekin guest.name bor.
5.2 Bu sintaksis JavaScript'ga kod qo'shadi
tsc bu klassni shunday JavaScript'ga aylantiradi:
class Guest {
name;
phone;
constructor(name, phone) {
this.name = name;
this.phone = phone;
}
// …
}Ko'rdingizmi: ikki maydon e'loni va ikki tayinlash qatori paydo bo'ldi. Ularni turlarni o'chirib olib bo'lmaydi — yangi kod yozish kerak. Odatdagi turlar (: string, private, readonly) esa shunchaki o'chiriladi.
TypeScript'ni o'rnatish darsida ko'rganingizdek, Node 24 .ts faylni turlarini o'chirib ishga tushiradi (type stripping). Kod qo'shish kerak bo'lgan sintaksisni u bajarmaydi. Yuqoridagi klassni node guest.ts bilan ishga tushirsak:
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript parameter property is not supported in strip-only modeTarjimasi: "TypeScript parameter property faqat-o'chirish rejimida qo'llab-quvvatlanmaydi". enum bilan ham xuddi shu xato chiqadi — buni keyingi darsda to'liq ko'ramiz.
5.3 erasableSyntaxOnly: xatoni oldindan ko'rish
Node'da yiqilishni kutmasdan, tsc ning o'zi bunday sintaksisni taqiqlashi mumkin. Buning uchun erasableSyntaxOnly ("faqat o'chiriladigan sintaksis") bayrog'i bor:
// @ts-options: {"erasableSyntaxOnly": true}
class Guest {
constructor(
public readonly name: string,
private phone: string,
) {}
}Kompilyator:
TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.Tarjimasi: "erasableSyntaxOnly yoqilganda bu sintaksisga ruxsat yo'q". Har parametr uchun bittadan. Mashqlar papkangizdagi tsconfig.json da ham, vazifalar da ham bu bayroq yoqilgan: testlar Node'da .ts dan to'g'ridan-to'g'ri ishlaydi. Shuning uchun kanon qoidasi: maydonlar oddiy e'lon bilan yoziladi, parameter properties ishlatilmaydi.
Parameter properties'ni ko'p mavjud loyihalarda uchratasiz — masalan, Angular va NestJS (keyingi qismlarda o'rganiladigan framework'lar) ularga tayanadi. O'qiy olish shart, yangi kodda esa bayroqqa qarab tanlanadi.
Tekshirib ko'ring: Qaysi biri
erasableSyntaxOnlybilan xato beradi:private x = 1;(maydon),readonly y: number;(maydon),constructor(readonly z: number) {}?
Javob
Faqat uchinchisi. private va readonly maydon oldida — tur ma'lumoti, ularni o'chirsa oddiy maydon qoladi. Konstruktor parametridagi readonly esa maydon yaratadi — bu yangi kod, o'chirib bo'lmaydi.
6. implements: klass va interfeys shartnomasi
6.1 Klass va'dani bajaradimi?
interface ni type va interface darsida obyekt shakli sifatida o'rgandik. Klass ham shu shaklga mos kelishini va'da qila oladi:
interface Printable {
copies: number;
print(): string;
}
class Receipt implements Printable {
print(): string {
return "Chek: 63 000 so'm";
}
}Kompilyator:
TS2420: Class 'Receipt' incorrectly implements interface 'Printable'.
Property 'copies' is missing in type 'Receipt' but required in type 'Printable'.Tarjimasi: "Receipt klassi Printable interfeysini noto'g'ri amalga oshiradi: Receipt da copies yo'q, Printable esa uni talab qiladi". implements — shartnoma: klass interfeysdagi hamma narsani bajaradi deb aytadi, tsc esa shuni tekshiradi.
Klass bir nechta interfeysni amalga oshira oladi — vergul bilan: class Receipt implements Printable, Named. Bu Kengaytirish darsidagi interface extends A, B ga o'xshaydi.
6.2 Tuzoq: implements turlarni bermaydi
Interfeys metod parametrining turini aytadi. Klass metodida uni qayta yozmasak-chi?
interface Discount {
apply(price: number): number;
}
class HalfPrice implements Discount {
apply(price) {
return price / 2;
}
}Kompilyator:
TS7006: Parameter 'price' implicitly has an 'any' type.Tarjimasi: "price parametrining turi yashirincha any bo'lib qoldi". TypeScript aytyapti: "bu parametrga tur yozmadingiz, men esa uni o'zim topa olmadim". implements faqat tekshiradi — klassga tur bermaydi. price ning turi interfeysdan olinmaydi, shuning uchun yashirin any. Klass metodlarida parametr turlarini har doim yozing: apply(price: number): number.
Shuning uchun implements ni ixtiyoriy deb bilish kerak: Strukturaviy tiplash tufayli HalfPrice obyekti Discount ga implements siz ham mos keladi. implements ning foydasi — xato klassning o'zida chiqadi, uni ishlatgan joyda emas.
7. abstract klass: chala qolip
7.1 O'zidan obyekt yasab bo'lmaydi
«Bahor» ikki xil to'lov qabul qiladi: naqd va karta. Ikkalasida summa va jami hisoblash bir xil, faqat komissiya har xil. Umumiy qismni ota klassga olamiz, komissiyani esa har bola klass o'zi yozsin:
abstract class Payment {
readonly amount: number;
constructor(amount: number) {
this.amount = amount;
}
abstract fee(): number;
total(): number {
return this.amount + this.fee();
}
}
class Cash extends Payment {
fee(): number {
return 0;
}
}
class Card extends Payment {
static readonly RATE = 0.01;
fee(): number {
return Math.round(this.amount * Card.RATE);
}
}
const payments: Payment[] = [new Cash(63000), new Card(63000)];
console.log(payments.map((p) => p.total())); // [ 63000, 63630 ]abstract class— abstrakt klass: undan to'g'ridan-to'g'rinewqilib bo'lmaydi, u faqat ota sifatida ishlatiladi. Kundalik o'xshatish: blanka qolipi — uni to'ldirib bo'lmaydi, avval nusxa olinadi.abstract fee(): number;— tanasiz metod: "har bola klass buni yozishi shart".total()— oddiy metod, hamma bolalarga umumiy. U hali yozilmaganfee()ni chaqira oladi.
Ikkita qoida buzilishi:
abstract class Payment {
abstract fee(): number;
}
class Transfer extends Payment {}
const p = new Payment();Kompilyator:
TS2515: Non-abstract class 'Transfer' does not implement inherited abstract member fee from class 'Payment'.
TS2511: Cannot create an instance of an abstract class.TS2515: "abstrakt bo'lmaganTransferklassiPaymentdan meros qolgan abstraktfeea'zosini amalga oshirmagan".TS2511: "abstrakt klassdan nusxa (instance) yaratib bo'lmaydi".
Mana shu ierarxiya chizmada. Strelka uchi bo'sh uchburchak — "meros oladi":
classDiagram
class Payment {
<<abstract>>
+amount number
+fee() number
+total() number
}
class Cash {
+fee() number
}
class Card {
+RATE number
+fee() number
}
Payment <|-- Cash
Payment <|-- Card7.2 abstract va interface — qachon qaysi?
interface |
abstract class |
|
|---|---|---|
Umumiy kod (total()) |
yo'q, faqat shakl | bor |
| Ishlash paytida | yo'q (o'chiriladi) | haqiqiy klass |
| Bir nechtasidan | implements A, B |
faqat bitta extends |
instanceof bilan tekshirish |
yo'q | bor |
Faqat shakl kerak bo'lsa — interface. Bola klasslar umumiy kodni ham bo'lishsin desangiz — abstract class. abstract so'zi faqat tur: JavaScript'da u oddiy klass bo'lib qoladi, shuning uchun erasableSyntaxOnly unga ruxsat beradi.
8. override: "men otaning metodini almashtiryapman"
Bola klass ota metodini qayta yozsa, oldiga override qo'yish mumkin. noImplicitOverride ("yashirin override yo'q") bayrog'i bilan esa — shart:
// @ts-options: {"noImplicitOverride": true}
class Notifier {
send(text: string): string {
return text;
}
}
class SmsNotifier extends Notifier {
send(text: string): string {
return `SMS: ${text}`;
}
override sned(text: string): string {
return text;
}
}Kompilyator:
TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'Notifier'.
TS4113: This member cannot have an 'override' modifier because it is not declared in the base class 'Notifier'.TS4114: "bu a'zo ota klassdagi a'zoni almashtiradi, shuning uchunoverridebo'lishi shart".TS4113: "bu a'zodaoverridebo'lishi mumkin emas, chunki ota klassda bunday a'zo yo'q".sned— harf xatosi.overridesiz bu yangi metod bo'lib qolardi vasendjim almashtirilmasdi.
Ikkala xabar ham bitta xavfdan saqlaydi: ota klassdagi metod nomi o'zgarsa yoki bolada xato yozilsa, aloqa jim uziladi. vazifalar bu bayroqni Strict bayroqlar oilasi qadamida yoqadi (o'lchovda 0 xato).
9. Ko'p uchraydigan xatolar
9.1 Maydonni e'lon qilmasdan this.x = …
TS2339: Property 'x' does not exist on type 'Order'. Tuzatish: klass tanasida x: Tur; e'lon qiling.
9.2 Maydon qiymatsiz qoldi
TS2564. Tuzatish: boshlang'ich qiymat, konstruktorda tayinlash yoki | undefined. ! — faqat oxirgi chora.
9.3 private ni xavfsizlik deb o'ylash
private faqat tsc ga ko'rinadi: obj["x"], JSON.stringify, JavaScript fayllari uni ko'radi. Tuzatish: haqiqiy yopiqlik — #.
9.4 erasableSyntaxOnly loyihasida parameter properties
TS1294, Node'da ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX. Tuzatish: oddiy maydon e'loni va konstruktorda tayinlash.
9.5 implements dan tur kutish
TS7006 — metod parametri any. Tuzatish: klass metodlarida parametr turlarini qayta yozing.
9.6 .ts faylda JSDoc tur
/** @type {Vazifa[]} */ #v = []; — .ts da never[]. Tuzatish: #v: Vazifa[] = [];.
10. Mashqlar
1-mashq (oson): Qaysi qator xato?
class Booking {
static readonly OPEN_HOUR = 10;
readonly guest: string;
protected people: number;
#table = 0;
constructor(guest: string, people: number) {
this.guest = guest;
this.people = people;
}
seat(table: number): void {
this.#table = table;
}
}
const b = new Booking("Dilshod aka", 4);
b.seat(7);
console.log(b.guest, Booking.OPEN_HOUR); // Dilshod aka 10Quyidagilarning qaysi biri tsc xatosi beradi? b.guest = "Ali" — xato kodi: [:TS2540]. b.people — xato kodi: [:TS2445]. b["people"] — xato bormi (ha/yo'q): .
Yechim
b.guest = …—TS2540:readonlymaydon konstruktordan keyin o'zgarmaydi.b.people—TS2445:protectedfaqat klass va bola klasslar ichida.b["people"]— xato yo'q: kvadrat qavsprivate/protectedni chetlab o'tadi. Shuning uchun haqiqiy yopiqlik kerak bo'lsa —#tablekabi.
2-mashq (o'rta): Kanon uslubiga o'tkazing
Bu klass parameter properties bilan yozilgan. Mashqlar papkangizdagi sozlamada (erasableSyntaxOnly) u TS1294 beradi, Node esa uni bajarmaydi:
// @ts-options: {"erasableSyntaxOnly": true}
class Waiter {
constructor(
public readonly name: string,
private tables: number[],
) {}
serves(table: number): boolean {
return this.tables.includes(table);
}
}Kompilyator:
TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.Ikki parametr — ikki xato: ikkalasi ham maydon yaratadi. Uni o'chiriladigan sintaksis bilan qayta yozing: oddiy maydonlar, readonly nom va haqiqatan yopiq stollar ro'yxati (#). Qo'shimcha: stollar tashqaridan o'zgarmasligi uchun konstruktor massivning nusxasini olsin.
Yechim
// @ts-options: {"erasableSyntaxOnly": true}
class Waiter {
readonly name: string;
readonly #tables: readonly number[];
constructor(name: string, tables: readonly number[]) {
this.name = name;
this.#tables = [...tables];
}
serves(table: number): boolean {
return this.#tables.includes(table);
}
}
const tables = [1, 2, 3];
const sardor = new Waiter("Sardor", tables);
tables.push(9);
console.log(sardor.serves(2), sardor.serves(9)); // true falsereadonly #tables: readonly number[]— maydon ham, massiv ham o'zgarmaydi (readonlysayoz bo'lgani uchun ikkalasi kerak).[...tables]— nusxa: tashqaridagitables.push(9)ofitsiantning ro'yxatiga ta'sir qilmadi.- Bayroq blokning birinchi qatorida yoqilgan —
tscxatosiz o'tkazdi.
3-mashq (qiyin): Bildirishnomalar
«Bahor» mehmonga buyurtma tayyor bo'lganini SMS yoki Telegram orqali xabar qiladi. Quyidagilarni yozing:
interface Named { readonly name: string }vainterface Sender { send(text: string): string }.abstract class Notifier implements Named, Sender:readonly name, yopiq#senthisoblagich, abstraktsend, oddiynotify(text)— hisoblagichni oshirib,"1. <send natijasi>"qaytarsin.SmsNotifier— telefon raqami (readonly #phone), xabarni 20 belgigacha qisqartiradi (SMS qisqa).TelegramNotifier— matnni to'liq yuboradi. Ikkalasidaoverride.
Yechim
// @ts-options: {"noImplicitOverride": true}
interface Named {
readonly name: string;
}
interface Sender {
send(text: string): string;
}
abstract class Notifier implements Named, Sender {
readonly name: string;
#sent = 0;
constructor(name: string) {
this.name = name;
}
abstract send(text: string): string;
notify(text: string): string {
this.#sent++;
return `${this.#sent}. ${this.send(text)}`;
}
}
class SmsNotifier extends Notifier {
readonly #phone: string;
constructor(phone: string) {
super("SMS");
this.#phone = phone;
}
override send(text: string): string {
return `${this.#phone} ga: ${text.slice(0, 20)}`;
}
}
class TelegramNotifier extends Notifier {
constructor() {
super("Telegram");
}
override send(text: string): string {
return `Telegram: ${text}`;
}
}
const list: Notifier[] = [
new SmsNotifier("+998 90 000 00 00"),
new TelegramNotifier(),
];
for (const n of list) {
console.log(n.notify("Buyurtmangiz tayyor, 5-stol"));
}
console.log(list[1]?.notify("Rahmat!"));Konsolda:
1. +998 90 000 00 00 ga: Buyurtmangiz tayyor,
1. Telegram: Buyurtmangiz tayyor, 5-stol
2. Telegram: Rahmat!#senthar obyektda alohida: SMS — 1, Telegram — avval 1, keyin 2.implements Named, Senderabstrakt klassda ham ishlaydi:sendabstrakt bo'lsa ham, shartnoma bajarildi deb hisoblanadi — bolalar uni yozishga majbur.list[1]?.notify— massiv elementiundefinedbo'lishi mumkin,?.buni hisobga oladi (nullvaundefined).super("SMS")— bola konstruktori avval ota konstruktorini chaqiradi (Meros).this.#phonefaqat undan keyin.
4-mashq: Vazifalar qadami — klass modullari .ts ga
vazifalar dagi uchta klass moduli .ts ga o'tadi: vazifa.js (Vazifa, VazifaXatosi), royxat.js (VazifalarRoyxati), prefiks-daraxti.js (PrefiksDaraxti). Klass xulqi o'zgarmaydi — faqat turlar.
- Branch:
refactor/klasslar-ts - Commit:
refactor: Vazifa, VazifalarRoyxati, PrefiksDaraxti — .ts, readonly, tanasi:# — ish vaqtida yopiq, readonly — tsc; parametr xususiyatlari yo'q
git mvbilan uchala faylni.tsga o'tkazing vanpx tsc --noEmitni ishga tushiring. Nechta xato chiqdi, qaysi kodlar ko'p?- Import yo'llari:
asosiy.js,holat.ts,paket.js,render.js,saqlash.tsva 7 ta test faylida./vazifa.js→./vazifa.ts(va qolgan ikkitasi).sw.jsdaVERSIYA = "v5-4". - JSDoc turlarini TypeScript sintaksisiga o'tkazing: maydonlar e'loni, parametrlar va natija turlari.
MAKS_UZUNLIK—static readonly,id—readonly,#matn—#qoladi. Parameter properties — yo'q. - Tekshiruv:
npm run build,npm test,npm run tip,npm run lint,npm run format:check.
Yechim
1. Faqat nomi o'zgartirilganda (tsc 7.0.2) — 53 ta xato:
- TS7006 (any parametr)35 xato
- TS2339 (yo'q xususiyat)11 xato
- TS2345 (argument)3 xato
- TS18046 (unknown)2 xato
- TS2349 + TS24882 xato
Manba: O'lchandi: tsc 7.0.2 --noEmit, vazifalar holatlar/15 → vazifa/royxat/prefiks-daraxti .ts, Node 24.21.0, 2026-10-06
Ko'pi — TS7006: JSDoc'dagi @param {number} id endi hisobga olinmaydi, parametrlar any. TS2339 lar ikki xil:
assets/js/vazifa.ts(14,10): error TS2339: Property 'kod' does not exist on type 'VazifaXatosi'.
assets/js/royxat.ts(131,42): error TS2339: Property 'id' does not exist on type 'never'.
assets/js/royxat.ts(176,49): error TS2349: This expression is not callable.
Type 'never' has no call signatures.Birinchisi — «Maydonlarni e'lon qilish» bo'limidagi holat: this.kod e'lonsiz. Qolgan 10 tasi va TS2349 — #vazifalar = [] va #tinglovchilar = []: JSDoc'dagi @type yo'qoldi, bo'sh massiv never[] bo'ldi. Uning elementida hech qanday xususiyat yo'q, chaqirib ham bo'lmaydi.
2–3. Turlar yozilgach — vazifa.ts:
// vazifa.ts — bitta vazifa va vazifalar xatosi
import type { VazifaMalumoti, VazifaXatosiKodi } from "./turlar.ts";
export class VazifaXatosi extends Error {
readonly kod: VazifaXatosiKodi;
constructor(
xabar: string,
sozlama?: ErrorOptions & { kod?: VazifaXatosiKodi },
) {
super(xabar, sozlama);
this.name = "VazifaXatosi";
this.kod = sozlama?.kod ?? "NOMALUM";
}
}
export class Vazifa {
// index.html dagi maxlength bilan bir xil bo'lsin
static readonly MAKS_UZUNLIK = 100;
// readonly — faqat konstruktorda yoziladi (tsc tekshiradi, JS'da
// yo'qoladi). #matn esa ish vaqtida ham yopiq: tashqaridan faqat
// getter va matnniOzgartir (tekshiruv bilan)
readonly id: number;
bajarildi: boolean;
#matn: string;
constructor(id: number, matn: string, bajarildi = false) {
this.id = id;
this.#matn = matn;
this.bajarildi = bajarildi;
}
static dan(malumot: VazifaMalumoti): Vazifa {
return new Vazifa(malumot.id, malumot.matn, malumot.bajarildi);
}
get matn(): string {
return this.#matn;
}
/** @returns matn qabul qilindimi */
matnniOzgartir(yangi: string): boolean {
const toza = yangi.trim();
if (toza === "" || toza.length > Vazifa.MAKS_UZUNLIK) {
return false;
}
this.#matn = toza;
return true;
}
almashtir(): void {
this.bajarildi = !this.bajarildi;
}
toJSON(): VazifaMalumoti {
return {
id: this.id,
matn: this.#matn,
bajarildi: this.bajarildi,
};
}
}ErrorOptions & { kod?: … }— kesishma: standartcauseva bizningkod.readonly idva#matn— ikki xil himoya, ataylab.idni o'qish hamma joyda kerak, faqat o'zgarmasin —tscyetarli.matnni esa faqat tekshiruvdan o'tgan holda o'zgartirish mumkin — bu ish vaqtidagi qoida,#kerak.bajarildi = false— standart qiymatdan tur chiqarildi (boolean).
royxat.ts da maydonlar endi tur bilan: #vazifalar: Vazifa[] = [], #tinglovchilar: Array<() => void> = [], iterator — *[Symbol.iterator](): Generator<Vazifa, void, undefined> (burchak qavsdagi turlarni Generics darsida o'qishni o'rganamiz). prefiks-daraxti.ts da @typedef Tugun → type Tugun, readonly #ildiz va bitta haqiqiy o'zgarish — JSDoc assertion o'rniga tekshiruv:
// Oldin (JS):
// const [tugun, soz] = /** @type {[Tugun, string]} */ (stek.pop());
const stek: Array<[Tugun, string]> = [[boshi, prefiks]];
let element = stek.pop();
while (element !== undefined) {
const [tugun, soz] = element;
// …
element = stek.pop();
}stek.pop() — [Tugun, string] | undefined. Oldin "bu yerda undefined bo'lmaydi" deb va'da berilardi. Endi tekshiruvning o'zi siklning sharti: undefined kelsa, sikl tugaydi (null va undefined).
Commit va PR:
git switch -c refactor/klasslar-ts
git mv assets/js/vazifa.js assets/js/vazifa.ts
git mv assets/js/royxat.js assets/js/royxat.ts
git mv assets/js/prefiks-daraxti.js assets/js/prefiks-daraxti.ts
# turlar, import yo'llari, sw.js VERSIYA
npm run build && npm test && npm run tip
npm run lint && npm run format:check
git add .
git commit -m "refactor: Vazifa, VazifalarRoyxati, PrefiksDaraxti — .ts, readonly" \
-m "# — ish vaqtida yopiq, readonly — tsc; parametr xususiyatlari yo'q"
git push -u origin refactor/klasslar-ts
gh pr create --fill
gh pr merge --mergeCommit sarlavhasi — 68 belgi (≤ 72). Natija: npm test — 137/137 (testlar endi .ts modullarni Node 24 type stripping bilan import qiladi), tip, lint, format:check — toza. Brauzer tekshiruvi (dist/) — 159/159. Diff: 17 fayl, +156 −201 — kod qisqardi: JSDoc izohlaridagi turlar ixchamroq TypeScript sintaksisiga o'tdi.
11. Real ishda
- Xizmat klasslari (Node backend, Angular, NestJS):
class OrderService { constructor(private readonly repo: OrderRepo) {} }— parameter properties'ning eng ko'p uchraydigan joyi. Endi uni o'qiysiz va nega ba'zi loyihalarda taqiqlanganini bilasiz. implementsshartnoma sifatida — bir interfeysning bir nechta amalga oshirilishi: haqiqiy to'lov tizimi va testdagi soxtasi (FakePayment implements PaymentGateway).abstract— kutubxonalarda "kengaytirish nuqtasi": siz faqat bitta metodni yozasiz, qolganini ota klass bajaradi.- Intervyu: "
privateva#farqi?", "abstract classvainterfacefarqi?", "implementsturlarni beradimi?" — TypeScript intervyusining klassik savollari.
Xulosa
- TypeScript klassida maydonlar e'lon qilinadi (
id: number;),strictesa ularning qiymat olishini tekshiradi (TS2564). public/protected/private— faqattsctekshiruvi, ishlash paytida yo'q. Haqiqiy yopiqlik — JavaScript'ning#.readonly— faqat konstruktorda yoziladi, lekin sayoz.static readonly— klass doimiysi.- Parameter properties JavaScript'ga kod qo'shadi:
erasableSyntaxOnly(TS1294) va Node type stripping ularni taqiqlaydi — kanonda oddiy maydonlar. implements— klass interfeysga mosligini tekshiradi, tur bermaydi.abstract class— umumiy kodli chala qolip.override+noImplicitOverride— ota bilan aloqa jim uzilmasin.
Keyingi dars: enum va uning muqobillari — enum qanday ishlaydi, nega Node uni bajarmaydi va as const obyekt + union bilan uni qanday almashtiramiz.
Manbalar
- TypeScript Handbook: "Classes" (Fields, readonly, Member Visibility, Parameter Properties, abstract, implements, override) — typescriptlang.org/docs/handbook/2/classes.html
- TSConfig:
strictPropertyInitialization,noImplicitOverride,erasableSyntaxOnly— typescriptlang.org/tsconfig - TypeScript 5.8 Release Notes:
--erasableSyntaxOnly— typescriptlang.org/docs/handbook/release-notes/typescript-5-8.html - Node.js hujjatlari: "Modules: TypeScript" (type stripping, qo'llab-quvvatlanmaydigan sintaksis) — nodejs.org/api/typescript.html
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!