تصنيف الفئات في TypeScript: كيفية التحقق من نوع الكائن

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

كيفية التحقق من نوع الفئة في TypeScript: من المبتدئ إلى المحترف

\n\n

هل سبق لك أن كتبت كودًا بلغة TypeScript، واستقبلت كائنًا من نوع غير معروف وفكرت: "من أنت أيها الغريب؟" هذا السؤال يؤرق آلاف المطورين - وليس من قبيل الصدفة أن موضوع التحقق من نوع الفئة في TypeScript حصد مئات الآلاف من المشاهدات على Stack Overflow. واليوم سنفهم مرة وإلى الأبد كيفية التحقق من أنواع الفئات في TypeScript بشكل صحيح.

\n\n

في هذه المقالة سوف تتعلم:

\n
    \n
  • لماذا لا يعمل typeof مع الفئات
  • \n
  • كيفية استخدام instanceof كأداة متعددة الاستخدامات
  • \n
  • ما هي حراس النوع (type guards) وكيف تنقذ كودك
  • \n
  • كيفية كتابة التحقق الخاص بك من النوع باستخدام is
  • \n
  • أمثلة حقيقية من الممارسة
  • \n
\n\n

هيا بنا!

\n\n

المشكلة: لماذا typeof عاجز هنا؟

\n\n

في JavaScript يوجد عامل typeof يعمل بشكل ممتاز مع الأنواع البدائية:

\n\n
typeof "hello" // "string"\ntypeof 42      // "number"\ntypeof true    // "boolean"
\n\n

ولكن عندما يتعلق الأمر بالفئات، يفشل typeof:

\n\n
class Dog {}\nclass Cat {}\n\nconst pet = new Dog();\n\ntypeof pet; // "object" — غير مفيد!\ntypeof Dog; // "function" — ليس هذا أيضًا
\n\n

لماذا؟ لأن الفئات في JavaScript هي مجرد سكر نحوي فوق دوال البناء (constructor functions). typeof يرى فقط "object" أو "function"، لكنه لا يميز أي فئة بالضبط.

\n\n

هنا يأتي دور التحقق من نوع الفئة في TypeScript - ترسانة كاملة من الأدوات التي ستساعدك على تحديد أي فئة تتعامل معها بدقة.

\n\n

الطريقة 1: instanceof - مساعدك الرئيسي

\n\n

الطريقة الأكثر مباشرة ووضوحًا للتحقق من نوع الفئة هي العامل instanceof. يتحقق مما إذا كانت الفئة موجودة في سلسلة النماذج الأولية (prototype chain) للكائن:

\n\n
class Animal {\n  name: string;\n  constructor(name: string) {\n    this.name = name;\n  }\n}\n\nclass Dog extends Animal {\n  bark() {\n    console.log("Woof!");\n  }\n}\n\nclass Cat extends Animal {\n  meow() {\n    console.log("Meow!");\n  }\n}\n\nfunction handleAnimal(animal: Animal) {\n  if (animal instanceof Dog) {\n    // TypeScript يعلم أن animal هو Dog\n    animal.bark();\n  } else if (animal instanceof Cat) {\n    animal.meow();\n  } else {\n    console.log(`Unknown animal: ${animal.name}`);\n  }\n}\n\nconst rex = new Dog("Rex");\nhandleAnimal(rex); // "Woof!"
\n\n

لاحظ: بعد التحقق animal instanceof Dog، يقوم TypeScript تلقائيًا بتضييق النوع (type narrowing) ويسمح باستدعاء دوال Dog دون أخطاء. هذا هو سحر حراس النوع (type guards) - المدافعين المدمجين عن الأنواع.

\n\n

متى لا يعمل instanceof؟

\n
    \n
  • عند العمل مع نوافذ/إطارات مختلفة (كائنات عامة مختلفة)
  • \n
  • إذا كانت الفئات محددة في وحدات مختلفة بإصدارات مختلفة
  • \n
  • عند التحقق من الواجهات (interfaces) (فهي غير موجودة في وقت التشغيل)
  • \n
\n\n

الطريقة 2: حراس النوع المخصصون مع العامل is

\n\n

أحيانًا لا يكون instanceof كافيًا. على سبيل المثال، قد ترغب في التحقق ليس فقط من الفئة ولكن أيضًا من شروط إضافية. هنا يأتي دور حراس النوع المخصصين مع الكلمة المفتاحية is:

\n\n
interface Bird {\n  fly(): void;\n  layEggs(): void;\n}\n\ninterface Fish {\n  swim(): void;\n  layEggs(): void;\n}\n\nfunction isFish(pet: Bird | Fish): pet is Fish {\n  return (pet as Fish).swim !== undefined;\n}\n\nfunction move(pet: Bird | Fish) {\n  if (isFish(pet)) {\n    // TypeScript يعلم: pet هو Fish\n    pet.swim();\n  } else {\n    pet.fly();\n  }\n}
\n\n

لاحظ الصياغة: pet is Fish في نوع الإرجاع. هذا يخبر TypeScript: "إذا أعادت هذه الدالة true، فإن المعامل pet هو Fish". الآن سيقوم TypeScript بتضييق النوع أينما استخدمت

المدونات

توصيات الكتب