🚀 احتراف الأنواع الشرطية Conditional Types في TypeScript
اليوم سننتقل إلى مستوى أكثر ذكاءً في التعامل مع الأنواع (Types). هل تخيلت يوماً أن يكون لديك "شرط" داخل تعريف النوع نفسه؟ تماماً كما نستخدم if في البرمجة، تتيح لنا TypeScript ميزة تسمى Conditional Types.
ببساطة، الأنواع الشرطية تسمح للنوع أن يتغير بناءً على تحقق شرط معين. إذا كان النوع "أ" هو نفسه النوع "ب"، فاستخدم النوع "س"، وإلا استخدم النوع "ص".
🧐 ما هي صيغة كتابة النوع الشرطي؟
تعتمد الأنواع الشرطية على صيغة تشبه إلى حد كبير "المعامل الشرطي المختصر" (Ternary Operator) الذي نعرفه في JavaScript.
الصيغة العامة:
T extends U ? X : Y
شرح الصيغة:
T extends U: هل النوعTقابل للتعيين (Assignable) للنوعU؟ (بمعنى: هلTهو نفسهUأو يرث منه؟).? X: إذا كانت الإجابة نعم، سيكون الناتج هو النوعX.: Y: إذا كانت الإجابة لا، سيكون الناتج هو النوعY.
🛠️ مثال بسيط جداً لتوضيح الفكرة
لنفرض أننا نريد إنشاء نوع يتغير بناءً على ما إذا كان المدخل نصاً string أو رقماً number.
// تعريف النوع الشرطي
type IsString<T> = T extends string ? "Yes, it is a string" : "No, it is not a string";
// تجربة النوع مع نص
type Test1 = IsString<string>;
// النتيجة: Test1 ستكون من نوع "Yes, it is a string"
// تجربة النوع مع رقم
type Test2 = IsString<number>;
// النتيجة: Test2 ستكون من نوع "No, it is not a string"
ماذا حدث هنا؟ 🤔
- أنشأنا نوعاً عاماً (Generic Type) يسمى
IsStringيأخذ متغيراًT. - سألنا TypeScript: هل
Tهوstring؟ - في
Test1أرسلناstring$\leftarrow$ تحقق الشرط $\leftarrow$ أصبحت النتيجة "Yes...". - في
Test2أرسلناnumber$\leftarrow$ لم يتحقق الشرط $\leftarrow$ أصبحت النتيجة "No...".
💡 مثال واقعي: تحديد نوع القيمة المرجعة
تخيل أن لديك دالة تستقبل قيمة، وإذا كانت هذه القيمة نصاً، تريد أن تعيد نصاً مضافاً إليه كلمة "Hello"، أما إذا كانت رقماً، تريد أن تعيد الرقم مضروباً في 2.
لنقم بتطبيق ذلك باستخدام Conditional Types:
// 1. تعريف النوع الشرطي: إذا كان T نصاً، فالنتيجة نص، وإلا فالنتيجة رقم
type ReturnTypeBasedOnInput<T> = T extends string ? string : number;
// 2. دالة تستخدم هذا النوع الشرطي
function processValue<T>(value: T): ReturnTypeBasedOnInput<T> {
if (typeof value === 'string') {
return `Hello ${value}` as ReturnTypeBasedOnInput<T>; // تحويل يدوي لأن TS تحتاج للتأكد
} else {
return (value as any) * 2 as ReturnTypeBasedOnInput<T>;
}
}
// تجربة الدالة
const result1 = processValue("Ahmed"); // result1 سيكون من نوع string
const result2 = processValue(10); // result2 سيكون من نوع number
ملاحظة تعليمية: استخدمنا as (Type Assertion) داخل الدالة لأن TypeScript أحياناً تجد صعوبة في ربط الشرط داخل النوع بالشرط داخل الكود البرمجي، وهذا أمر طبيعي في هذا المستوى.
⚠️ نقاط هامة يجب تذكرها
- المرونة: الأنواع الشرطية تجعل الكود الخاص بك "ديناميكياً"، بحيث يتكيف النوع تلقائياً مع البيانات المدخلة.
- الارتباط بالـ Generics: لا يمكن عمل
Conditional Typesبدون استخدام الـ Generics (مثل<T>) لأننا نحتاج لمتغير لنقوم بفحصه. - الترتيب: يتم فحص الشرط من اليسار إلى اليمين، وبمجرد تحقق الشرط يتم اختيار النوع المقابل له.
🎓 ملخص سريع
- Conditional Type: هو نوع يتغير بناءً على شرط.
- الصيغة:
T extends U ? X : Y. - الهدف: زيادة دقة الأنواع في المشاريع الكبيرة لضمان عدم تمرير بيانات خاطئة.
⏭️ ماذا سنتعلم في الدرس القادم؟
الآن بعد أن تعلمت كيف تجعل الأنواع "تتخذ قرارات" عبر الشروط، سننتقل إلى موضوع مكمل ورائع جداً وهو "Mapped Types". سنتعلم كيف نقوم بـ "تحويل" أو "تكرار" مجموعة من الأنواع لإنشاء أنواع جديدة بناءً على أنواع قديمة. انتظرنا في الدرس القادم! 🌟
🎓 اختبر معلوماتك
التعليقات
شاركنا رأيك أو أسئلتك حول هذا المقال