التأمل والاستبطان في TypeScript: كيف ينظر الكود إلى نفسه
\n\nتخيل برنامجًا قادرًا على تحليل نفسه في وقت التشغيل. يمكنه معرفة أنواع متغيراته، وما هي الخصائص التي تمتلكها الكائنات، وحتى اتخاذ قرار بناءً على هذه المعلومات. يبدو وكأنه سحر؟ في الواقع، هذا هو التأمل والاستبطان — تقنيات قوية للبرمجة الفوقية متاحة أيضًا في TypeScript.
\n\nفي هذه المقالة، سنوضح الفرق بين التأمل والاستبطان، وكيفية استخدامهما في TypeScript، ولماذا قد يكون ذلك مفيدًا في المشاريع الحقيقية. لا نظرية مملة — فقط كود حي وأمثلة عملية.
\n\nما هو الاستبطان والتأمل؟
\n\nدعنا نوضح الأمور فورًا. في البرمجة، غالبًا ما يتم الخلط بين هذين المصطلحين، لكن هناك فرق:
\n\n- \n
- الاستبطان — هو قدرة البرنامج على مراقبة هيكله. يمكنك معرفة الخصائص التي يمتلكها الكائن، وما هو نوعه، لكن لا يمكنك تغييرها. \n
- التأمل — هو مستوى أكثر تقدمًا: لا ينظر البرنامج إلى نفسه فحسب، بل يغير سلوكه في وقت التشغيل. على سبيل المثال، استدعاء الأساليب ديناميكيًا أو إنشاء مثيلات جديدة للفئات. \n
في JavaScript، التي يعتمد عليها TypeScript، يتم تنفيذ التأمل من خلال Reflect وProxy. لكن TypeScript يضيف طبقة خاصة به — الكتابة الثابتة، التي تختفي جزئيًا أثناء التجميع. وهنا يبدأ الجزء المثير للاهتمام.
استبطان الأنواع: حواجز الأنواع و typeof
\n\nأبسط طريقة للنظر داخل الكود هي استخدام حواجز الأنواع. وهي تركيبات تتحقق من نوع البيانات في وقت التشغيل:
\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nfunction processValue(value: unknown) {\n if (isString(value)) {\n // TypeScript يعلم أن value هي سلسلة نصية\n console.log(value.toUpperCase());\n } else {\n console.log('هذا ليس سلسلة نصية');\n }\n}\n\nلاحظ value is string — هذا هو مسند النوع. يخبر TypeScript أنه بعد التحقق، المتغير ينتمي إلى نوع معين. هذا استبطان خالص: نحن ننظر إلى النوع، لكننا لا نغيره.
التأمل من خلال واجهة Reflect API
\n\nكائن Reflect هو آلية تأمل مدمجة في JavaScript. يسمح بتنفيذ إجراءات كانت تتم سابقًا بطرق "سحرية"، لكنها الآن موحدة. إليك بعض الأمثلة:
const user = {\n name: 'أليكسي',\n age: 30,\n};\n\n// استبطان — الحصول على قائمة المفاتيح\nconsole.log(Reflect.ownKeys(user)); // ['name', 'age']\n\n// تأمل — قراءة خاصية ديناميكيًا\nconst propertyName = 'name';\nconsole.log(Reflect.get(user, propertyName)); // 'أليكسي'\n\n// تأمل — تعيين خاصية ديناميكيًا\nReflect.set(user, 'name', 'ماريا');\nconsole.log(user.name); // 'ماريا'\n\nلماذا Reflect أفضل من الطريقة القديمة user[prop]؟ أولاً، يعيد boolean لعمليات التعيين، مما يسهل التحقق. ثانيًا، يعمل بشكل صحيح مع الـ Proxy وواصفات الخصائص. بالنسبة لـ TypeScript، هذا مهم بشكل خاص، لأن التأمل يسمح بتجاوز الكتابة الثابتة عندما يكون ذلك ضروريًا حقًا.
المزينات: تأمل معزز
\n\nالمزينات هي، بلا شك، المثال الأبرز على التأمل في TypeScript. تسمح بتعليق الفئات والطرق والخصائص والمعاملات، ثم تغيير سلوكها. منذ إصدار TypeScript 5.0، أصبحت المزينات قياسية (المرحلة 3).
\n\nإليك كيف يبدو مزين بسيط لتسجيل استدعاء طريقة:
\n\nfunction logMethod(\n target: any,\n propertyKey: string,\n descriptor: PropertyDescriptor\n) {\n const originalMethod = descriptor.valu