الانتقال إلى المحتوى الرئيسي
الوحدة 2 · الدرس 2 من 24/14 في الدورة~15 min
دروس الوحدة (2/2)

النقابات والتضييق

في العالم الحقيقي، لا تحتوي المتغيرات واستجابات واجهة برمجة التطبيقات (API) دائمًا على نوع واحد ثابت. تقدم TypeScript Union Types للتعامل مع التباين، وType Narrowing للعمل عليها بأمان في وقت التشغيل.


أنواع الاتحاد

يسمح نوع الاتحاد للمتغير بقبول قيم من أنواع مختلفة. ويتم التعبير عنها باستخدام رمز الشريط العمودي (|):

TS
let result: number | string;
result = 42; // Valid
result = 'Error 404'; // Valid

ومع ذلك، عند العمل مع نوع موحد، لا يمكننا استدعاء الأساليب التي تنتمي إلى نوع واحد فقط من الأنواع مباشرة (على سبيل المثال، لا يمكننا استدعاء .toUpperCase() إذا كان المتغير يمكن أيضًا أن يكون number). يجب علينا أولا "تضييق" النوع.


اكتب تضييق

تضييق النوع هي العملية التي يقوم فيها TypeScript بتحليل هياكل تدفق التحكم (مثل if أو switch) لاستنتاج نوع أكثر تحديدًا لمتغير في وقت التشغيل.

هناك عدة طرق لإجراء التضييق:

1. المشغل typeof

مثالية للتمييز بين الأنواع البدائية:

TS
function printLength(value: string | number) {
  if (typeof value === 'string') {
    // TypeScript knows 'value' is a string here
    console.log(value.length);
  } else {
    // TypeScript knows 'value' is a number here
    console.log(value.toFixed(2));
  }
}

2. المشغل in

يستخدم للتحقق من وجود خاصية معينة على كائن:

TS
interface Fish {
  swim: () => void;
}
interface Bird {
  fly: () => void;
}

function move(animal: Fish | Bird) {
  if ('swim' in animal) {
    animal.swim(); // Narrowing to Fish
  } else {
    animal.fly(); // Narrowing to Bird
  }
}

النقابات التمييزية

يتكون نمط الاتحادات التمييزية من إنشاء كائنات تشترك في خاصية مشتركة ذات قيمة حرفية فريدة (تسمى discriminator). يتعرف TypeScript على هذا التمييز ويقوم تلقائيًا بتضييق نطاق الكتابة داخل الكتل الشرطية.

TS
interface SuccessResponse {
  status: 'success'; // Literal discriminator
  data: string;
}

interface ErrorResponse {
  status: 'error'; // Literal discriminator
  errorMessage: string;
}

type ApiResponse = SuccessResponse | ErrorResponse;

function handleResponse(response: ApiResponse) {
  if (response.status === 'success') {
    console.log('Data received:', response.data);
  } else {
    console.error('An error occurred:', response.errorMessage);
  }
}

جربه بنفسك

التمرين 1: أنواع الاتحاد

تمرين#ts.m2.l2.e1
المحاولات: 0جارٍ التحميل…

قم بتعريف متغير يسمى id والذي يمكن أن يكون رقمًا أو سلسلة. قم بتهيئته أولاً بالرقم 101، ثم قم بتعيين قيمة السلسلة "USER-101".

جارٍ تحميل المحرر…
إظهار التلميح

استخدم | عامل لربط الرقم والسلسلة في إعلان المتغير Let.

الحل متاح بعد 3 من المحاولات

التمرين 2: تضييق النوع الأساسي

تمرين#ts.m2.l2.e2
المحاولات: 0جارٍ التحميل…

قم بإنشاء وظيفة باسم formatInput تقبل إدخال معلمة من النوع سلسلة أو رقم. إذا كان الإدخال عبارة عن سلسلة، فسيتم إرجاع الإدخال المحول إلى أحرف كبيرة. إذا كان رقمًا، فقم بإرجاع الإدخال مضروبًا في 2. وحدد الأنواع بشكل صريح.

جارٍ تحميل المحرر…
إظهار التلميح

استخدم typeof input === 'string' داخل كتلة if لتفرع السلوك.

الحل متاح بعد 3 من المحاولات

التمرين 3: التضييق باستخدام "in"

تمرين#ts.m2.l2.e3
المحاولات: 0جارٍ التحميل…

بالنظر إلى الواجهتين Car (مع طريقة القيادة) والقارب (مع طريقة الشراع)، اكتب دالة باسم moveVehicle تقبل مركبة معلمة من النوع Car أو Boat. إذا كانت السيارة تحتوي على خاصية محرك الأقراص، فقم بتنفيذ طريقة محرك الأقراص (). بخلاف ذلك، قم بتنفيذ طريقة الشراع ().

جارٍ تحميل المحرر…
إظهار التلميح

استخدم عامل التشغيل in في النموذج "drive" في السيارة لتضييق الواجهة.

الحل متاح بعد 3 من المحاولات

التمرين 4: شكل الاتحاد التمييزي

تمرين#ts.m2.l2.e4
المحاولات: 0جارٍ التحميل…

تحديد نوع الشكل وهو اتحاد نوعين: الدائرة والمربع. تحتوي الدائرة على خاصية لطيفة تم تعيينها على "دائرة" (القيمة الحرفية) ونصف القطر (رقم). يحتوي Square على خاصية نوع تم تعيينها على "مربع" (القيمة الحرفية) وجانب (رقم). ثم اكتب دالة getArea تقبل الشكل من النوع Shape وترجع المنطقة كرقم (للدائرة Math.PI * radius * radius، للجانب المربع * الجانب).

جارٍ تحميل المحرر…
إظهار التلميح

استخدم Shape.kind === 'circle' داخل getArea لتمييز النوع وحساب المنطقة الصحيحة.

الحل متاح بعد 3 من المحاولات