العامل ?. في TypeScript: كيف يعمل وما اسمه الحقيقي

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

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

ابدأ الدورة

مقدمة: السؤال الذي يقلق المبتدئين

\n

هل سبق لك أن كتبت كودًا في TypeScript وحصلت على خطأ مثل Cannot read property 'name' of undefined؟ ألم مألوف، أليس كذلك؟ خاصة عند العمل مع بيانات قادمة من الخادم، أو مع كائنات متداخلة بعمق. في تلك اللحظات تحديدًا يطرح السؤال: «هل يوجد في TypeScript عامل يسمح بالوصول الآمن إلى الخصائص دون الخوف من تعطل كل شيء؟»

\n

على Stack Overflow، حظي هذا السؤال بآلاف المشاهدات. والإجابة هي نعم، يوجد مثل هذا العامل. بل إنه موجود أيضًا في JavaScript (بدءًا من ES2020)، ويعمل في TypeScript «خارج الصندوق». يُسمى optional chaining (السلسلة الاختيارية)، ويظهر كالرمز المألوف للجميع ?.. في هذه المقالة، لن نشرح فقط كيفية استخدامه، بل سننظر أيضًا تحت الغطاء: كيف يحول مترجم TypeScript هذه البنية الأنيقة إلى كود JavaScript آمن.

\n\n

ما اسم العامل ?. في TypeScript؟

\n

لنبدأ بالأهم. في مجتمع المطورين، يُسمى هذا العامل بأسماء مختلفة:

\n
    \n
  • Optional chaining (السلسلة الاختيارية) — الاسم الرسمي في مواصفات ECMAScript.
  • \n
  • عامل الوصول الآمن (Safe navigation operator) — جاء من لغات أخرى مثل C# وSwift.
  • \n
  • عامل الشرط null (Null-conditional operator) — موجود في وثائق Microsoft.
  • \n
\n

لكن الجوهر واحد: ?. يسمح بالوصول إلى خاصية كائن، وإذا كان الكائن يساوي null أو undefined، فبدلاً من الخطأ نحصل ببساطة على undefined. هذا ليس سحرًا، بل مجرد سكر نحوي (syntactic sugar) يجعل الكود أنظف وأكثر أمانًا.

\n\n

البنية الأساسية

\n

البنية بسيطة للغاية. بدلاً من كتابة:

\n
if (user && user.profile && user.profile.name) {\n    console.log(user.profile.name);\n}
\n

تكتب:

\n
console.log(user?.profile?.name);
\n

إذا كان user هو undefined، فإن السلسلة بأكملها تتوقف، ويتم طباعة undefined في وحدة التحكم. لا أخطاء، ولا تحققات إضافية. روعة!

\n\n

كيف يعمل هذا تحت الغطاء: ترجمة TypeScript إلى JavaScript

\n

TypeScript هو طبقة فوق JavaScript. لا ينفذ الكود مباشرة، بل يترجمه إلى JS عادي. لذلك دعونا نرى ما يتحول إليه user?.profile?.name الأنيق بعد الترجمة.

\n\n

مثال: سلسلة اختيارية بسيطة

\n

الكود الأصلي في TypeScript:

\n
const name = user?.profile?.name;
\n

بعد الترجمة (الهدف هو ES5):

\n
var name = user === null || user === void 0 ? void 0 : user.profile === null || user.profile === void 0 ? void 0 : user.profile.name;
\n

ماذا يحدث هنا؟ يُنشئ المترجم عاملًا ثلاثيًا (ternary operator) يتحقق من كل مستوى من التداخل للتأكد من أنه ليس null أو undefined. إذا كانت القيمة null أو undefined، يتم إرجاع void 0 (وهي طريقة موثوقة للحصول على undefined في المحركات القديمة). إذا لم يكن كذلك، نستمر. هذا هو في الأساس نفس الكود «اليدوي» الذي كنا نكتبه سابقًا، ولكن الآن يولده الجهاز.

\n\n

مثال: سلسلة اختيارية مع استدعاء دالة

\n

العامل ?. لا يعمل فقط مع الخصائص، بل أيضًا مع استدعاءات الدوال. لنفترض أن لدينا طريقة getAddress قد تكون غير موجودة:

\n
const address = user?.getAddress?.();
\n

بعد الترجمة:

\n
var address = user === null || user === void 0 ? void 0 : (typeof user.getAddress === "function" ? user.getAddress() : void 0);
\n

لاحظ: المترجم لا يتحقق فقط من null، بل يتأكد أيضًا من أن getAddress هي دالة قبل استدعائها. إذا لم تكن دالة، يتم إرجاع undef

المدونات

توصيات الكتب