TypeScript

Klasslar va konfiguratsiya

TypeScript klasslari โ€” JavaScript klasslarining kuchaytirilgan ko'rinishi. JS'dagi barcha imkoniyatlar saqlanadi, ustiga kirish modifikatorlari, implements va boshqa foydali vositalar qo'shiladi. Ushbu yakuniy darsda klasslarni, enumni va loyihaning yuragi bo'lgan tsconfig.json faylini o'rganamiz.

TypeScript klasslari

TypeScript klassi JavaScript klassiga o'xshaydi, lekin bir muhim farqi bor: maydonlar (fields) oldindan e'lon qilinishi va turlarga ega bo'lishi kerak:

class Foydalanuvchi {
  ism: string;
  yosh: number;

  constructor(ism: string, yosh: number) {
    this.ism = ism;
    this.yosh = yosh;
  }

  salomBer(): string {
    return "Salom, men " + this.ism;
  }
}

let u = new Foydalanuvchi("Ali", 25);
console.log(u.salomBer());

Diqqat qiling: ism: string va yosh: number maydonlari konstruktordan oldin e'lon qilingan. JavaScript'da bu shart emas edi, TypeScript'da esa maydonlarni oldindan bildirish kerak (yoki konstruktorda parametr xossalari orqali).

Kirish modifikatorlari: public, private, protected

TypeScript maydon va metodlarga kirish modifikatorlarini qo'shadi. Ular xossaga qaysi joydan murojaat qilish mumkinligini belgilaydi:

class HisobRaqam {
  public egasi: string;
  private balans: number;

  constructor(egasi: string, boshlang: number) {
    this.egasi = egasi;
    this.balans = boshlang;
  }

  qoshish(summa: number): void {
    this.balans += summa;
  }

  balansniKorish(): number {
    return this.balans;
  }
}

let h = new HisobRaqam("Ali", 1000);
h.qoshish(500);
console.log(h.balansniKorish()); // 1500
console.log(h.egasi);            // "Ali" โ€” OK
console.log(h.balans);           // Xato: 'balans' private
private va protected โ€” faqat kompilyatsiya paytida tekshiriladi. Tayyor JavaScript'da bu xossalarga baribir kirish mumkin. Haqiqiy maxfiylik uchun JS'ning # (private field) sintaksisini ishlating.

readonly maydonlar va parametr xossalari

Klass maydonini readonly qilib, uni faqat konstruktorda o'rnatiladigan va keyin o'zgartirib bo'lmaydigan qilish mumkin:

class Mahsulot {
  readonly id: number;
  nom: string;

  constructor(id: number, nom: string) {
    this.id = id;
    this.nom = nom;
  }
}

let m = new Mahsulot(1, "Kitob");
m.nom = "Daftar"; // OK
m.id = 2;         // Xato: 'id' read-only

TypeScript qulay qisqartma beradi: konstruktor parametriga to'g'ridan-to'g'ri modifikator yozsangiz, u avtomatik maydon bo'lib o'rnatiladi. Buni parametr xossalari deyiladi:

class Nuqta {
  // modifikatorlar maydonni avtomatik yaratadi:
  constructor(
    public x: number,
    public y: number,
    private nom: string
  ) {}
}

let p = new Nuqta(1, 2, "A");
console.log(p.x, p.y); // 1 2
Parametr xossalari ko'p yozuvni qisqartiradi: public x: number deb yozish bilan maydon e'loni va this.x = x tayinlash birdaniga bajariladi.

Interfeysni amalga oshirish (implements)

Klass biror interfeysga mos kelishini kafolatlash uchun implements kalit so'zi ishlatiladi. Bu klass interfeysdagi barcha xossa va metodlarni albatta ta'minlashini majburlaydi:

interface Shakl {
  yuza(): number;
  perimetr(): number;
}

class Doira implements Shakl {
  constructor(private radius: number) {}

  yuza(): number {
    return Math.PI * this.radius * this.radius;
  }

  perimetr(): number {
    return 2 * Math.PI * this.radius;
  }
}

let d = new Doira(5);
console.log(d.yuza());

Agar klass interfeysdagi biror metodni yozishni unutsa, kompilyator xato beradi:

class Kvadrat implements Shakl {
  constructor(private tomon: number) {}
  yuza(): number { return this.tomon * this.tomon; }
  // perimetr yozilmagan!
}
// Xato: Class 'Kvadrat' incorrectly implements interface 'Shakl'.
// Property 'perimetr' is missing.
extends (meros) va implements (shartnoma) farqli: extends boshqa klassdan kod meros oladi; implements esa faqat interfeysga mos kelishni majburlaydi, kod bermaydi. Bir klass bir vaqtda extends va implements qila oladi.

enum โ€” sanaladigan qiymatlar to'plami

enum (enumeration) โ€” bog'liq nomlangan doimiylar to'plamini yaratish uchun ishlatiladi. Masalan, hafta kunlari yoki holatlar. JavaScript'da enum yo'q โ€” bu sof TypeScript qo'shimchasi:

enum Yonalish {
  Yuqori,
  Past,
  Chap,
  Ong
}

let y: Yonalish = Yonalish.Yuqori;
console.log(y); // 0 (standart holatda 0 dan boshlab raqamlanadi)

Standart holatda enum a'zolari 0, 1, 2, ... sonlariga bog'lanadi. Lekin siz ochiq qiymatlar berishingiz ham mumkin โ€” ayniqsa matnli (string) enum ko'p ishlatiladi, chunki u o'qishga qulayroq:

enum Holat {
  Kutilyapti = "KUTILYAPTI",
  Tayyor = "TAYYOR",
  Bekor = "BEKOR"
}

let h: Holat = Holat.Tayyor;
console.log(h); // "TAYYOR"
Oddiy holatlar uchun ko'p jamoalar enum o'rniga literal union turlarni afzal ko'radi (masalan type Holat = "tayyor" | "bekor"), chunki ular tayyor JS'da qo'shimcha kod yaratmaydi. Ikkalasi ham to'g'ri yechim.

tsconfig.json โ€” loyiha konfiguratsiyasi

Haqiqiy loyihalarda har safar tsc fayl.ts yozmaymiz. Buning o'rniga loyiha ildizida tsconfig.json faylini yaratamiz. U TypeScript kompilyatoriga qanday ishlashni aytadi. Uni avtomatik yaratish uchun:

tsc --init

Bu buyruq izohlar bilan to'la tsconfig.json yasaydi. Uning soddalashtirilgan asosiy ko'rinishi quyidagicha:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "noEmitOnError": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

Asosiy sozlamalar nimani anglatadi:

tsconfig.json mavjud bo'lsa, endi shunchaki tsc deb yozamiz โ€” u konfiguratsiyani o'qib, barcha fayllarni birdaniga kompilyatsiya qiladi:

tsc          # butun loyihani kompilyatsiya qiladi
tsc --watch  # o'zgarishlarni kuzatib turadi
strict: true โ€” TypeScript'dan maksimal foyda olishning kaliti. U strictNullChecks, noImplicitAny kabi bir nechta muhim tekshiruvni birdaniga yoqadi. Yangi loyihalarda uni doim yoqish tavsiya etiladi.

Xulosa