Məzmuna keç
Educora
Orta18 dəq5 / 8

Birləşmə tipləri və daraltma

Tipləri `|` və `&` ilə birləşdir, `typeof`, `in` və müqayisələrlə tipi daralt, diskriminant birləşmələr qur və öz tip mühafizəçilərini yaz.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • Birləşmə (A | B) və kəsişmə (A & B) tiplərini yazmaq və fərqləndirmək
  • Tipi typeof, in, === və null yoxlaması ilə daraltmaq
  • Diskriminant birləşmə qurmaq və bütün halların işləndiyini never ilə yoxlamaq
  • value is T şəklində tip mühafizəçisi yazmaq

Həyatda qiymətlər çox vaxt bir neçə formada olur. Sifarişin nömrəsi 42 də ola bilər, 'AB-17' də. Ödəniş ya kartla, ya da nağd edilir. Server ya verilənləri, ya da xəta mesajını qaytarır. Belə halları tək bir tiplə təsvir etmək olmur — «bu və ya o» lazımdır. TypeScript bunun üçün birləşmə tipləri, onlarla təhlükəsiz işləmək üçün isə daraltma təklif edir.

Birləşmə tipləri

number | string tipi «ya ədəd, ya da sətir» deməkdir. Belə qiymətlə yalnız birləşmənin bütün üzvlərində olan əməliyyatları etmək olar. Ədədin toUpperCase metodu olmadığı üçün aşağıdakı kod səhvdir:

TypeScript
function shout(id: number | string): string {
  return id.toUpperCase();
}
Text
ids.ts:2:13 - error TS2339: Property 'toUpperCase' does not exist on type 'string | number'.
  Property 'toUpperCase' does not exist on type 'number'.

2   return id.toUpperCase();
              ~~~~~~~~~~~
Tərif
Daraltma

Kompilyatorun sənin yoxlamalarını (typeof, in, ===, instanceof və s.) izləyərək if və ya switch budağının içində qiymətin tipini dəqiqləşdirməsi. Budağın içində birləşmədən yalnız uyğun üzv qalır.

TypeScript
function formatId(id: number | string): string {
  if (typeof id === 'number') {
    return `#${id.toString().padStart(4, '0')}`;
  }
  return id.toUpperCase();
}

console.log(formatId(42));
console.log(formatId('ab-17'));
Gözlənilən nəticə
#0042
AB-17
if daxilində id number-dir; return-dən sonra isə yalnız string qalır.

Daraltma alətləri

YoxlamaNə vaxt istifadə olunur
typeof x === 'string'primitiv tiplər: string, number, boolean və s.
x === nullnull və ya undefined-ı ayırmaq
'cardNumber' in xfərqli xassələri olan obyektlər
x instanceof Datesinif nüsxələri
x.kind === 'circle'diskriminant birləşmələr (aşağıda)
TypeScript
type Card = { cardNumber: string };
type Cash = { amount: number };

function describePayment(p: Card | Cash): string {
  if ('cardNumber' in p) {
    return `Card ending in ${p.cardNumber.slice(-4)}`;
  }
  return `Cash: ${p.amount} AZN`;
}

function greet(name: string | null): string {
  if (name === null) {
    return 'Hello, guest!';
  }
  return `Hello, ${name}!`;
}

console.log(describePayment({ cardNumber: 'XXXX-XXXX-XXXX-4821' }));
console.log(describePayment({ amount: 20 }));
console.log(greet(null), greet('Leyla'));
Gözlənilən nəticə
Card ending in 4821
Cash: 20 AZN
Hello, guest! Hello, Leyla!

Diskriminant birləşmələr

Ən güclü üsul birləşmənin hər üzvünə eyni adlı, amma fərqli literal qiymətli xassə verməkdir — adətən kind və ya type. Bu xassəyə diskriminant deyilir. switch (shape.kind) yazanda hər case daxilində TypeScript fiqurun dəqiq növünü bilir və yalnız onun xassələrinə icazə verir.

TypeScript
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; side: number }
  | { kind: 'rectangle'; width: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.side ** 2;
    case 'rectangle':
      return shape.width * shape.height;
  }
}

const shapes: Shape[] = [
  { kind: 'circle', radius: 1 },
  { kind: 'square', side: 3 },
  { kind: 'rectangle', width: 2, height: 5 },
];

for (const s of shapes) {
  console.log(s.kind, area(s).toFixed(2));
}
Gözlənilən nəticə
circle 3.14
square 9.00
rectangle 10.00

Sabah komandadan kimsə birləşməyə üçbucaq əlavə etsə, nə olacaq? Bütün halların işləndiyinə zəmanət vermək üçün default budağında qiyməti never tipli dəyişənə yazırlar. never «heç bir qiymət» deməkdir: bütün hallar işlənibsə, oraya heç nə çatmır. İşlənməmiş hal qalıbsa, kompilyator dərhal xəbər verir:

TypeScript
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; side: number }
  | { kind: 'triangle'; base: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.side ** 2;
    default: {
      const unhandled: never = shape;
      return unhandled;
    }
  }
}
Text
area.ts:13:13 - error TS2322: Type '{ kind: "triangle"; base: number; height: number; }' is not assignable to type 'never'.

13       const unhandled: never = shape;
               ~~~~~~~~~
Səhv mesajı hansı halın unudulduğunu dəqiq göstərir — üçbucaq.

Öz tip mühafizəçilərin

Yoxlamanı ayrıca funksiyaya çıxarmaq istəsən, adi boolean qaytarmaq kifayət etmir — TypeScript funksiyanın içinə baxıb nəticə çıxarmır. Qaytarılan tipi value is string kimi yazanda funksiya tip mühafizəçisinə (type guard) çevrilir: true qaytarırsa, kompilyator qiymətin string olduğuna inanır. Bu, xüsusilə filter ilə rahatdır:

TypeScript
function isString(value: unknown): value is string {
  return typeof value === 'string';
}

const inputs: unknown[] = ['Baku', 42, 'Ganja', null, 'Shaki'];
const cities = inputs.filter(isString);

console.log(cities.map((city) => city.toUpperCase()).join(', '));
Gözlənilən nəticə
BAKU, GANJA, SHAKI
Mühafizəçi sayəsində cities unknown[] yox, string[] tiplidir və toUpperCase çağırmaq olar.

Kəsişmə tipləri

Birləşmə «birindən biri» deməkdirsə, kəsişmə A & B «hamısı birlikdə» deməkdir: qiymət hər iki tipin bütün xassələrinə malik olmalıdır. Kəsişmə ilə kiçik, təkrar istifadə olunan hissələrdən böyük tiplər yığmaq rahatdır:

TypeScript
type HasId = { id: number };
type HasDate = { createdAt: string };
type Post = HasId & HasDate & { title: string };

const post: Post = { id: 1, createdAt: '2025-09-01', title: 'Hello, TypeScript' };
console.log(`${post.id}: ${post.title} (${post.createdAt})`);
Gözlənilən nəticə
1: Hello, TypeScript (2025-09-01)

Əsas fikirlər

  • A | B — «ya A, ya B»; birbaşa yalnız bütün üzvlərdə olan xassələri istifadə etmək olar.
  • typeof, ===, in və instanceof yoxlamaları budağın içində tipi daraldır.
  • Diskriminant birləşmədə hər üzvün kind kimi literal xassəsi olur; switch onu mükəmməl daraldır.
  • default budağında never tipinə mənimsətmə unudulmuş halları kompilyasiya zamanı tapır.
  • value is T qaytaran funksiya tip mühafizəçisidir; A & B isə hər iki tipin bütün xassələrini birləşdirir.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
if (typeof id === 'number') { ... } blokunun içində id: number | string parametri hansı tipdədir?