{"checkpoints":{"s-at-1":[{"q":"<p>يخشى مراجع أن يصل رقم البطاقة إلى <code dir=\"ltr\">saveAddress</code>. ما الصحيح؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">type</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Address</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#953800;--shiki-dark:#FFA657\">line1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; </span><span style=\"color:#953800;--shiki-dark:#FFA657\">city</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> };</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> saveAddress</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">a</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Address</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) { </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* sends a to the address service */</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> form</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { line1: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'12 Nile St'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, city: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'Cairo'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, cardNumber: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'4242 4242 4242 4242'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> };</span></span>\n<span class=\"line\"><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">saveAddress</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(form);</span></span></code></pre></div>\n","options":[{"text":"يفشل في الترجمة، لأن <code dir=\"ltr\">cardNumber</code> خاصية زائدة.","why":"فحوص الخصائص الزائدة لا تنطبق إلا على الكائنات الحرفية الطازجة. و<code dir=\"ltr\">form</code> متغيّر، فالحقل الإضافي مسموح."},{"text":"يُزيل TypeScript الحقل <code dir=\"ltr\">cardNumber</code> قبل الاستدعاء، لأن <code dir=\"ltr\">Address</code> لا يعلنه.","why":"تُمحى الأنواع؛ لا تضيف خصائص ولا تُزيلها وقت التشغيل أبدًا."},{"text":"لا يمرّ في الترجمة إلا إذا كتبت <code dir=\"ltr\">form as Address</code>.","why":"لا حاجة إلى تأكيد. التنميط البنيوي يقبل <code dir=\"ltr\">form</code> أصلًا، وهذا بالضبط مصدر الخطر."},{"text":"يمرّ في الترجمة، ويُمرَّر الكائن كله وقت التشغيل بما فيه رقم البطاقة؛ انسخ الحقول التي تحتاجها صراحة.","why":"صحيح. التنميط البنيوي يسمح بالخصائص الإضافية، فالإصلاح الآمن الوحيد بناء كائن جديد فيه <code dir=\"ltr\">line1</code> و<code dir=\"ltr\">city</code>."}],"answer":3},{"q":"<p>قيمة <code dir=\"ltr\">quantityInStock</code> هي <code dir=\"ltr\">null</code> أثناء فحص المخزون، و<code dir=\"ltr\">0</code> حين ينفد المنتج. أيّ تغيير يجعل هذه التسمية صحيحة؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> stockLabel</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">quantityInStock</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> number</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> |</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> null</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  if</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">!</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">quantityInStock) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'Checking stock…'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> quantityInStock </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">===</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> ?</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'Sold out'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> :</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> `${</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">quantityInStock</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">} left`</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n","options":[{"text":"استبدل <code dir=\"ltr\">!quantityInStock</code> بـ <code dir=\"ltr\">quantityInStock === null</code>.","why":"صحيح. فحص الصدقية يلتقط <code dir=\"ltr\">0</code> أيضًا، فلا يمكن الوصول إلى ‘Sold out’. والمقارنة مع <code dir=\"ltr\">null</code> تفصل بين المعنيين."},{"text":"أضف <code dir=\"ltr\">if (typeof quantityInStock === 'number')</code> بعد السطر الأول.","why":"بعد السطر الأول تكون <code dir=\"ltr\">0</code> قد أعادت ‘Checking stock…’؛ ولا يستطيع فحص لاحق إنقاذها."},{"text":"اكتب <code dir=\"ltr\">quantityInStock!</code> في المقارنة.","why":"تأكيد عدم الفراغ يغيّر النوع فقط، لا مسار التنفيذ. وتبقى <code dir=\"ltr\">0</code> تأخذ الفرع الأول."},{"text":"احذف نوع الإرجاع <code dir=\"ltr\">: string</code> كي يستنتجه TypeScript.","why":"نوع الإرجاع ليس المشكلة؛ فحص الصدقية هو المشكلة."}],"answer":0},{"q":"<p>يضيف Cartwheel المدفوعات. الدفعة المعلّقة ليس لها معرّف تحصيل؛ والمحصَّلة لها دائمًا <code dir=\"ltr\">captureId</code>؛ والمستردّة لها دائمًا <code dir=\"ltr\">captureId</code> و<code dir=\"ltr\">refundedAt</code> و<code dir=\"ltr\">refundCents</code>. أيّ نوع يجعل التركيبات المستحيلة تفشل في الترجمة؟</p>","options":[{"text":"<code dir=\"ltr\">{ status: 'pending' | 'captured' | 'refunded'; captureId?: string; refundedAt?: string; refundCents?: number }</code>","why":"الحقول الاختيارية مستقلة عن <code dir=\"ltr\">status</code>، فما زالت الدفعة المستردّة دون <code dir=\"ltr\">refundCents</code> تمرّ في الترجمة."},{"text":"<code dir=\"ltr\">{ status: string; details: Record&lt;string, unknown&gt; }</code>","why":"هذا يقبل أي حالة وأي تفاصيل، فلا يمنع شيئًا ويفرض التحويلات في كل مكان."},{"text":"union من ثلاثة أنواع كائنات، لكلٍّ منها <code dir=\"ltr\">status</code> حرفي والحقول التي تملكها تلك الحالة بالضبط، وكلها إلزامية.","why":"صحيح. كل شكل يحمل بياناته الإلزامية، و<code dir=\"ltr\">status</code> الحرفي يتيح للـ narrowing إيجاد الشكل الصحيح."},{"text":"<code dir=\"ltr\">Partial&lt;{ status: string; captureId: string; refundedAt: string; refundCents: number }&gt;</code>","why":"جعل كل حقل اختياريًا يسمح بحالات مستحيلة أكثر حتى من الأصل."}],"answer":2},{"q":"<p>ما هو <code dir=\"ltr\">ShippingMethod</code>؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> SHIPPING_FEES</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { standard: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">499</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, express: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1299</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">satisfies</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Record</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">number</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">type</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> ShippingMethod</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> keyof</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> typeof</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> SHIPPING_FEES</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">string</code>، لأن الكائن فُحص مقابل <code dir=\"ltr\">Record&lt;string, number&gt;</code>","why":"هذا ما سيعطيك إياه التعليق النوعي. أما <code dir=\"ltr\">satisfies</code> فتفحص الكائن وتحتفظ بنوعه المستنتَج."},{"text":"<code dir=\"ltr\">'standard' | 'express'</code>","why":"صحيح. النوع المستنتَج فيه المفتاحان المكتوبان بالضبط، فتعطي <code dir=\"ltr\">keyof</code> اسميهما الحرفيين."},{"text":"<code dir=\"ltr\">number</code>، نوع القيم","why":"<code dir=\"ltr\">keyof</code> تعطي أسماء الخصائص لا القيم؛ أما القيم فستكون <code dir=\"ltr\">(typeof SHIPPING_FEES)[ShippingMethod]</code>."},{"text":"<code dir=\"ltr\">'standard' | 'express' | string</code>","why":"لا يوجد index signature في النوع المستنتَج، فليس <code dir=\"ltr\">string</code> جزءًا من union المفاتيح."}],"answer":1},{"q":"<p>في <code dir=\"ltr\">switch (order.status)</code> حالة <code dir=\"ltr\">case 'canceled':</code> بحرف L واحد، ولا تتطابق أبدًا. أيّ تغيير يحوّل هذا الخطأ الإملائي إلى خطأ ترجمة؟</p>","options":[{"text":"أضف فرع <code dir=\"ltr\">default:</code> يسجّل الحالات المجهولة.","why":"هذا يساعد وقت التشغيل، لكن الـ compiler ما زال يقبل الحالة المكتوبة خطأً."},{"text":"علّق <code dir=\"ltr\">order</code> بنوع <code dir=\"ltr\">any</code> كي يفحص TypeScript كل حالة.","why":"<code dir=\"ltr\">any</code> تُطفئ الفحص؛ ستُخفي الخطأ الإملائي أكثر."},{"text":"أعِد كتابة الـ <code dir=\"ltr\">switch</code> كسلسلة <code dir=\"ltr\">if</code>/<code dir=\"ltr\">else</code>.","why":"مع <code dir=\"ltr\">status</code> من نوع <code dir=\"ltr\">string</code>، تمرّ <code dir=\"ltr\">=== 'canceled'</code> في الترجمة بالسرور نفسه الذي تمرّ به الـ <code dir=\"ltr\">case</code>."},{"text":"حدّد نوع <code dir=\"ltr\">status</code> كـ union من الحالات الحرفية الخمس بدل <code dir=\"ltr\">string</code>.","why":"صحيح. مقابل union حرفي، يُبلَّغ عن <code dir=\"ltr\">case 'canceled':</code> بأنها غير قابلة للمقارنة مع <code dir=\"ltr\">OrderStatus</code>."}],"answer":3}],"s-at-2":[{"q":"<p>أيّ توقيع يجعل <code dir=\"ltr\">firstWhere(orders, (o) =&gt; o.status === 'shipped')</code> تُعيد <code dir=\"ltr\">Order | undefined</code>، و<code dir=\"ltr\">firstWhere(products, …)</code> تُعيد <code dir=\"ltr\">Product | undefined</code>، مع تحديد نوع <code dir=\"ltr\">o</code> في الـ callback؟</p>","options":[{"text":"<code dir=\"ltr\">function firstWhere&lt;T&gt;(items: T[], predicate: (item: T) =&gt; boolean): T | undefined</code>","why":"صحيح. يُستنتج <code dir=\"ltr\">T</code> من <code dir=\"ltr\">items</code>، ثم يعطي الـ callback نوع معامله ويعطي النتيجة نوعها."},{"text":"<code dir=\"ltr\">function firstWhere(items: unknown[], predicate: (item: unknown) =&gt; boolean): unknown</code>","why":"دون معامل نوع، يكون <code dir=\"ltr\">o</code> في الـ callback من نوع <code dir=\"ltr\">unknown</code> وكذلك النتيجة؛ وسيضطر المستدعون إلى التحويل."},{"text":"<code dir=\"ltr\">function firstWhere&lt;T&gt;(items: unknown[], predicate: (item: T) =&gt; boolean): T | undefined</code>","why":"لم يعد لـ <code dir=\"ltr\">T</code> موقع استنتاج سوى الـ callback غير المعلَّق، فينتهي به الأمر <code dir=\"ltr\">unknown</code>."},{"text":"<code dir=\"ltr\">function firstWhere(items: any[], predicate: (item: any) =&gt; boolean): any</code>","why":"هذا يمرّ في الترجمة في كل مكان ولا يفحص شيئًا؛ الأخطاء الإملائية في الـ callback تمرّ دون أن يلاحظها أحد."}],"answer":0},{"q":"<p>ما نوع <code dir=\"ltr\">t.value</code>؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> tag</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#953800;--shiki-dark:#FFA657\">T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">value</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { value };</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> t</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> tag</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'shipped'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">'shipped'</code>","why":"كانت القيمة الحرفية ستنجو لو كان <code dir=\"ltr\">T</code> مقيَّدًا بـ <code dir=\"ltr\">string</code> أو معرَّفًا بـ <code dir=\"ltr\">const</code>. هنا هي متداخلة في كائن فتتّسع."},{"text":"<code dir=\"ltr\">unknown</code>","why":"وجد TypeScript مرشّحًا، الوسيط النصي، فلا يلجأ إلى <code dir=\"ltr\">unknown</code>."},{"text":"<code dir=\"ltr\">any</code>","why":"الـ inference لا ينتج <code dir=\"ltr\">any</code> أبدًا من وسيط نصي حرفي."},{"text":"<code dir=\"ltr\">string</code>","why":"صحيح. <code dir=\"ltr\">T</code> غير مقيَّد ويظهر داخل الكائن المُعاد، فيتّسع المرشّح الحرفي."}],"answer":3},{"q":"<p>يجب أن تُرفض <code dir=\"ltr\">setDefault(['standard', 'express'], 'overnight')</code> لأن <code dir=\"ltr\">'overnight'</code> ليست أحد الخيارات. أيّ توقيع يفعل ذلك؟</p>","options":[{"text":"<code dir=\"ltr\">function setDefault&lt;const T&gt;(options: T[], fallback: T)</code>","why":"ما زال <code dir=\"ltr\">fallback</code> موقع استنتاج، فتُضاف <code dir=\"ltr\">'overnight'</code> إلى <code dir=\"ltr\">T</code> بدل أن تُفحص."},{"text":"<code dir=\"ltr\">function setDefault&lt;T extends string&gt;(options: T[], fallback: T)</code>","why":"القيد يحتفظ بالقيم الحرفية، لكن <code dir=\"ltr\">fallback</code> ما زال يساهم بمرشّح، فيكبر <code dir=\"ltr\">T</code> ليشمل <code dir=\"ltr\">'overnight'</code>."},{"text":"<code dir=\"ltr\">function setDefault&lt;T extends string&gt;(options: T[], fallback: NoInfer&lt;T&gt;)</code>","why":"صحيح. القيد يُبقي الخيارات حرفية، و<code dir=\"ltr\">NoInfer</code> تجعل <code dir=\"ltr\">fallback</code> للفحص فقط."},{"text":"<code dir=\"ltr\">function setDefault&lt;T&gt;(options: T[], fallback: NoInfer&lt;T&gt;)</code>","why":"دون قيد أولي، تُستنتج المصفوفة على أنها <code dir=\"ltr\">string[]</code>، فيجتاز أي نص الفحص."}],"answer":2},{"q":"<p>مستدعو عميل Cartwheel يكتبون <code dir=\"ltr\">api.get&lt;Order&gt;('/orders/1042')</code> في كل مكان، وفي الأسبوع الماضي كتب أحدهم <code dir=\"ltr\">api.get&lt;Order[]&gt;('/orders/1042')</code>. ما الإصلاح الأفضل؟</p>","options":[{"text":"اجعل العميل مفهرسًا بنوع خريطة مسارات، فيُبحث عن نوع الاستجابة من المسار ولا يمرّر المستدعون أي وسيط نوع.","why":"صحيح. يصبح المسار موقع الاستنتاج الوحيد، ولا يعود نوع الاستجابة الخاطئ شيئًا يستطيع المستدعي كتابته."},{"text":"أضف قاعدة ESLint تتطلّب وسيط نوع في كل استدعاء لـ <code dir=\"ltr\">get</code>.","why":"هذا يفرض كتابة وسيط نوع، لا كتابة الصحيح منه؛ والخطأ كان وسيط نوع خاطئًا."},{"text":"غيّر معامل النوع الافتراضي لـ <code dir=\"ltr\">get</code> إلى <code dir=\"ltr\">any</code>.","why":"هذا يُزيل ما تبقّى من فحص ويجعل الاستخدام الخاطئ أكثر صمتًا."},{"text":"اجعل <code dir=\"ltr\">get</code> تُعيد <code dir=\"ltr\">unknown</code> ودع كل مستدعٍ يحوّل بـ <code dir=\"ltr\">as</code>.","why":"هذا ينقل الادّعاء غير المفحوص نفسه إلى <code dir=\"ltr\">as</code> في كل موضع استدعاء؛ إنه أأمن من <code dir=\"ltr\">any</code> لكنه ليس إصلاحًا."}],"answer":0},{"q":"<p>تُستدعى <code dir=\"ltr\">function useQuery&lt;TData, TKey extends string&gt;(key: TKey, fetcher: () =&gt; Promise&lt;TData&gt;)</code> هكذا <code dir=\"ltr\">useQuery&lt;Order&gt;('order-1042', loadOrder)</code> فتفشل مع “Expected 2 type arguments, but got 1”. ما الإصلاح الأفضل في موضع الاستدعاء؟</p>","options":[{"text":"اكتب <code dir=\"ltr\">useQuery&lt;Order, string&gt;(…)</code> في كل مكان.","why":"يمرّ في الترجمة، لكن المفتاح يفقد نوعه الحرفي ويصبح كل موضع استدعاء أكثر ضجيجًا."},{"text":"احذف <code dir=\"ltr\">&lt;Order&gt;</code> ودع معاملَي النوع يُستنتجان، <code dir=\"ltr\">TData</code> من نوع إرجاع <code dir=\"ltr\">loadOrder</code>.","why":"صحيح. وسائط النوع الصريحة إمّا كلها أو لا شيء؛ ودون أيٍّ منها يستنتج TypeScript الاثنين من الوسائط."},{"text":"غلّف المفتاح بـ <code dir=\"ltr\">NoInfer</code>.","why":"<code dir=\"ltr\">NoInfer</code> تتحكّم في مواقع الاستنتاج؛ لا تجعل وسائط النوع الصريحة جزئية."},{"text":"حوّل نتيجة الاستدعاء إلى <code dir=\"ltr\">any</code>.","why":"الخطأ يتعلّق بوسائط النوع في الاستدعاء، ولا يستطيع تحويل على النتيجة إصلاحه."}],"answer":1}],"s-at-3":[{"q":"<p>ما هو <code dir=\"ltr\">F</code>؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">type</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Flags</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#953800;--shiki-dark:#FFA657\">T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { [</span><span style=\"color:#953800;--shiki-dark:#FFA657\">K</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> in</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> keyof</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> as</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">[</span><span style=\"color:#953800;--shiki-dark:#FFA657\">K</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">extends</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> boolean</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> ?</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> K</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> :</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> never</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">[</span><span style=\"color:#953800;--shiki-dark:#FFA657\">K</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] };</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">type</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> F</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Flags</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;{ </span><span style=\"color:#953800;--shiki-dark:#FFA657\">giftWrap</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> boolean</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; </span><span style=\"color:#953800;--shiki-dark:#FFA657\">note</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; </span><span style=\"color:#953800;--shiki-dark:#FFA657\">express</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> boolean</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }>;</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">{ giftWrap: boolean; note: never; express: boolean }</code>","why":"تحويل مفتاح إلى <code dir=\"ltr\">never</code> في جملة <code dir=\"ltr\">as</code> يُزيله كليًا؛ لا يُبقيه بنوع <code dir=\"ltr\">never</code>."},{"text":"<code dir=\"ltr\">'giftWrap' | 'express'</code>","why":"هذه ستكون نتيجة فهرسة الـ mapped type بـ <code dir=\"ltr\">[keyof T]</code>. أما هذا النوع فيحتفظ بشكل الكائن."},{"text":"<code dir=\"ltr\">{ note: string }</code>","why":"الشرط يُبقي الخصائص من نوع boolean ويُسقط الباقي، لا العكس."},{"text":"<code dir=\"ltr\">{ giftWrap: boolean; express: boolean }</code>","why":"صحيح. جملة <code dir=\"ltr\">as</code> ترسل المفاتيح التي ليست قيمها boolean إلى <code dir=\"ltr\">never</code>، فتُسقط من النتيجة."}],"answer":3},{"q":"<p>ما هو <code dir=\"ltr\">X</code>؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"5\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">type</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> IdOf</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#953800;--shiki-dark:#FFA657\">T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> extends</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#953800;--shiki-dark:#FFA657\">id</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> infer</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> I</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> I</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> :</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> never</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">type</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> X</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> IdOf</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;{ </span><span style=\"color:#953800;--shiki-dark:#FFA657\">id</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> number</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#953800;--shiki-dark:#FFA657\">id</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#953800;--shiki-dark:#FFA657\">name</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }>;</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">number | string</code>","why":"صحيح. يتوزّع الشرط على الـ union: عضوان يلتقطان نوع <code dir=\"ltr\">id</code> لديهما، والثالث يصبح <code dir=\"ltr\">never</code> ويختفي."},{"text":"<code dir=\"ltr\">never</code>، لأن الـ union ككل ليس فيه <code dir=\"ltr\">id</code> مشترك","why":"هذه ستكون النتيجة غير التوزيعية. معامل النوع المجرّد يجعل الفحص يُنفَّذ لكل عضو."},{"text":"<code dir=\"ltr\">number</code>، من العضو الأول فقط","why":"كل عضو يُعالَج، وتُجمع النتائج."},{"text":"<code dir=\"ltr\">unknown</code>، لأن <code dir=\"ltr\">infer</code> لا تستطيع الالتقاط من union","why":"<code dir=\"ltr\">infer</code> تعمل لكل عضو بعد التوزيع، فيكون كل التقاط دقيقًا."}],"answer":0},{"q":"<p>ما هو <code dir=\"ltr\">`on${Capitalize&lt;'shipped' | 'cancelled'&gt;}`</code>؟</p>","options":[{"text":"<code dir=\"ltr\">'onshipped' | 'oncancelled'</code>","why":"<code dir=\"ltr\">Capitalize</code> تكبّر الحرف الأول من كل عضو قبل أن يُضمّ إلى <code dir=\"ltr\">on</code>."},{"text":"<code dir=\"ltr\">`on${string}`</code>","why":"مع أعضاء حرفية في الداخل، يتوسّع القالب إلى نصوص محدّدة بدل نمط."},{"text":"<code dir=\"ltr\">'onShipped' | 'onCancelled'</code>","why":"صحيح. يتوزّع الـ union عبر القالب، ويُكبَّر الحرف الأول من كل عضو."},{"text":"<code dir=\"ltr\">'onShipped | Cancelled'</code>","why":"الـ unions لا تُضمّ في نص واحد؛ كل عضو ينتج نصه الحرفي الخاص."}],"answer":2},{"q":"<p>ما هو <code dir=\"ltr\">Draft&lt;{ readonly id: number; status: string }&gt;</code>؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"6\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">type</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Draft</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#953800;--shiki-dark:#FFA657\">T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-readonly</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#953800;--shiki-dark:#FFA657\">K</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> in</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> keyof</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">[</span><span style=\"color:#953800;--shiki-dark:#FFA657\">K</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] };</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">{ readonly id: number; status: string }</code>، دون تغيير","why":"المعدِّلان <code dir=\"ltr\">-readonly</code> و<code dir=\"ltr\">?</code> يغيّران الخاصيتين كلتيهما."},{"text":"<code dir=\"ltr\">{ id: number; status: string }</code>","why":"تُطبَّق <code dir=\"ltr\">-readonly</code>، لكن <code dir=\"ltr\">?</code> تجعل أيضًا كل خاصية اختيارية."},{"text":"<code dir=\"ltr\">{ readonly id?: number; status?: string }</code>","why":"البادئة <code dir=\"ltr\">-</code> تُزيل <code dir=\"ltr\">readonly</code> من <code dir=\"ltr\">id</code>؛ ولا يُضاف إلا معدِّل الاختيارية."},{"text":"<code dir=\"ltr\">{ id?: number; status?: string }</code>","why":"صحيح. <code dir=\"ltr\">-readonly</code> تنزع معدِّل القراءة فقط و<code dir=\"ltr\">?</code> تجعل كل خاصية اختيارية."}],"answer":3},{"q":"<p>ما هو <code dir=\"ltr\">ElementOf&lt;readonly string[]&gt;</code>؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"7\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">type</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> ElementOf</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#953800;--shiki-dark:#FFA657\">T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> extends</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">infer</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> E</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)[] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> E</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> :</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">string</code>","why":"المصفوفة <code dir=\"ltr\">readonly string[]</code> غير قابلة للإسناد إلى النمط القابل للتعديل <code dir=\"ltr\">(infer E)[]</code>، فلا يُؤخذ الفرع الصادق."},{"text":"<code dir=\"ltr\">readonly string[]</code>","why":"صحيح. المصفوفات للقراءة فقط تفتقد methods التعديل، فلا تطابق نمط مصفوفة قابلة للتعديل؛ استخدم <code dir=\"ltr\">readonly (infer E)[]</code> في النمط."},{"text":"<code dir=\"ltr\">never</code>","why":"الفرع الكاذب يُعيد <code dir=\"ltr\">T</code> نفسه، لا <code dir=\"ltr\">never</code>."},{"text":"<code dir=\"ltr\">unknown</code>","why":"لا شيء هنا ينتج <code dir=\"ltr\">unknown</code>؛ النمط ببساطة لا يطابق."}],"answer":1}],"s-at-4":[{"q":"<p>ما الخطأ في هذا الكود؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"8\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> id</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> JSON</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">parse</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(body).orderId </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> OrderId</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">cancelOrder</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(id);</span></span></code></pre></div>\n","options":[{"text":"لا شيء؛ يُفحص الوسم حين تُنفَّذ <code dir=\"ltr\">cancelOrder</code>.","why":"الوسوم لا وجود لها وقت التشغيل، فلا شيء يفحص أي شيء حين تُنفَّذ الدالة."},{"text":"<code dir=\"ltr\">JSON.parse</code> تُعيد نصًا دائمًا، فيكون <code dir=\"ltr\">orderId</code> نصًا.","why":"<code dir=\"ltr\">JSON.parse</code> تُعيد ما يحتويه JSON أيًّا كان؛ والمشكلة هنا هي التحويل غير المفحوص."},{"text":"التحويل يسِم قيمة لم يتحقّق منها أحد؛ حلّلها بالمُنشئ الذكي، مثل <code dir=\"ltr\">toOrderId(…)</code>، بدلًا من ذلك.","why":"صحيح. الوسم لا معنى له إلا حين يُطبَّق بعد التحقّق، في مكان واحد."},{"text":"الـ branded types لا يمكن استخدامها مع قيم أتت من JSON.","why":"يمكن ذلك، ما دامت قيمة JSON تمرّ بمُنشئ متحقِّق أولًا."}],"answer":2},{"q":"<p>مستدعٍ لـ <code dir=\"ltr\">charge(): Result&lt;Receipt, PaymentError&gt;</code> يكتب <code dir=\"ltr\">if (result.error) showError(result.error)</code>. ماذا يحدث؟</p>","options":[{"text":"لا يمرّ في الترجمة، لأن <code dir=\"ltr\">error</code> لا توجد إلا في عضو الإخفاق؛ افحص <code dir=\"ltr\">result.ok</code> أولًا.","why":"صحيح. الوصول إلى خاصية في union يتطلّب وجودها في كل عضو، فتضيّق النوع بالمميِّز."},{"text":"يمرّ في الترجمة ويعمل، لأن <code dir=\"ltr\">error</code> تكون <code dir=\"ltr\">undefined</code> عند النجاح.","why":"عضو النجاح لا يعلن <code dir=\"ltr\">error</code> إطلاقًا، فيرفض TypeScript قراءتها قبل التضييق."},{"text":"يمرّ في الترجمة، لكن الشرط كاذب دائمًا.","why":"لا يمرّ في الترجمة أصلًا."},{"text":"يرمي خطأً وقت التشغيل حين تكون النتيجة نجاحًا.","why":"قراءة خاصية غائبة تعطي <code dir=\"ltr\">undefined</code> في JavaScript، لكن TypeScript يوقف الكود قبل أن يُنفَّذ أصلًا."}],"answer":0},{"q":"<p>يعرض خادم Cartwheel السلة الأولية في الصفحة كـ JSON. البيانات السيئة هناك تعني نشرًا معطوبًا، لا شيئًا يستطيع العميل إصلاحه. كيف يجب أن يتعامل العميل معها؟</p>","options":[{"text":"type predicate داخل <code dir=\"ltr\">if</code>، مع الرجوع إلى سلة فارغة حين يفشل.","why":"عرض سلة فارغة بصمت يُخفي خطأ النشر عن الجميع، بما في ذلك أدوات المراقبة لديك."},{"text":"<code dir=\"ltr\">const cart = JSON.parse(text) as Cart</code>.","why":"التحويل غير المفحوص يجعل النشر المعطوب يظهر كأخطاء مربكة بعيدة عن السبب."},{"text":"محلّل يُعيد <code dir=\"ltr\">Result</code>، مع إعادة المحاولة حين يفشل.","why":"إعادة المحاولة لا تُصلح بيانات عرضها الخادم خطأً؛ هذا ليس إخفاقًا متوقَّعًا قابلًا للتعافي."},{"text":"دالة تأكيد تُستدعى مرة واحدة عند البدء وترمي خطأً واضحًا، تلتقطه أداة الإبلاغ عن الأخطاء لديك.","why":"صحيح. البيانات السيئة هنا خطأ برمجي، فالفشل بصوت عالٍ عند الحدود هو السلوك الصحيح."}],"answer":3},{"q":"<p>ما المشكلة في method الـ emitter هذه؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"9\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">on</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(event: keyof Events, handler: (</span><span style=\"color:#953800;--shiki-dark:#FFA657\">payload</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Events</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">[</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">keyof</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Events</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> void</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">): </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">void</span></span></code></pre></div>\n","options":[{"text":"الدوال السهمية لا يمكن تمريرها كـ handlers.","why":"أي دالة بتوقيع متوافق يمكن تمريرها؛ المسألة هي أيّ توقيع هذا."},{"text":"حمولة الـ handler هي الـ union من حمولات كل الأحداث، لا حمولة الحدث المشترَك فيه.","why":"صحيح. دون معامل نوع <code dir=\"ltr\">K</code>، لا شيء يربط الاسم بحمولته. استخدم <code dir=\"ltr\">on&lt;K extends keyof Events&gt;(event: K, handler: (payload: Events[K]) =&gt; void)</code>."},{"text":"تتّسع أسماء الأحداث إلى <code dir=\"ltr\">string</code>، فتُقبل الأخطاء الإملائية.","why":"<code dir=\"ltr\">keyof Events</code> هو union من أسماء الأحداث، فما زالت الأخطاء الإملائية مرفوضة؛ ما يضيع هو الحمولة."},{"text":"لا شيء؛ هذا هو التوقيع الموصى به.","why":"يمرّ في الترجمة، لكن على كل handler أن يضيّق حمولة union ليس فيها مميِّز يُضيَّق عليه."}],"answer":1},{"q":"<p>تضيف <code dir=\"ltr\">'on-hold'</code> إلى <code dir=\"ltr\">OrderStatus</code>. أيّ جدول بحث يفشل في الترجمة إلى أن يحصل على مدخل <code dir=\"ltr\">'on-hold'</code>؟</p>","options":[{"text":"<code dir=\"ltr\">const LABELS = { … } satisfies Record&lt;OrderStatus, string&gt;</code>","why":"صحيح. <code dir=\"ltr\">satisfies</code> تفحص الكائن مقابل الـ record الكامل، فيكون المفتاح الناقص خطأً."},{"text":"<code dir=\"ltr\">const LABELS: Partial&lt;Record&lt;OrderStatus, string&gt;&gt; = { … }</code>","why":"<code dir=\"ltr\">Partial</code> تجعل كل مفتاح اختياريًا، فالحالة الناقصة مسموحة."},{"text":"<code dir=\"ltr\">const LABELS: Record&lt;string, string&gt; = { … }</code>","why":"أي مفاتيح نصية مسموحة، فلا يعرف الجدول أيّ الحالات موجودة."},{"text":"<code dir=\"ltr\">const LABELS = { … } as Record&lt;OrderStatus, string&gt;</code>","why":"التأكيد لا يفحص إلا تداخل الأنواع، فلا يُبلَّغ عن المفتاح الناقص."}],"answer":0}],"s-at-5":[{"q":"<p>سكربت يُشغَّل بـ <code dir=\"ltr\">node checkout.ts</code> (تجريد الأنواع المدمج في Node) يحتوي <code dir=\"ltr\">enum Channel { Web = 'web' }</code> ويفشل عند البدء. أيّ خيار في الـ compiler كان سيعلّم الـ enum أثناء <code dir=\"ltr\">tsc</code>؟</p>","options":[{"text":"<code dir=\"ltr\">isolatedModules</code>","why":"يلتقط البُنى التي تحتاج معلومات من ملفات أخرى، مثل إعادة تصدير نوع دون <code dir=\"ltr\">type</code>، لكنه يسمح بالـ enums."},{"text":"<code dir=\"ltr\">verbatimModuleSyntax</code>","why":"يتحكّم في طريقة توليد الـ imports والـ exports؛ وما زالت الـ enums مسموحة."},{"text":"<code dir=\"ltr\">erasableSyntaxOnly</code>","why":"صحيح. يرفض الصياغة التي تولّد كودًا وقت التشغيل، مثل الـ enums، التي لا يستطيع تجريد الأنواع التعامل معها."},{"text":"<code dir=\"ltr\">noEmit</code>","why":"يمنع <code dir=\"ltr\">tsc</code> من كتابة الملفات؛ ولا يضيف أي فحوص."}],"answer":2},{"q":"<p>لماذا يمكن أن يُنفَّذ هذا الخصم من البطاقة والسلة غير مقفلة؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"10\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">async</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> pay</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">cartId</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">needsLock</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> boolean</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  if</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (needsLock) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    using</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> lock</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> acquireCartLock</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(cartId);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  await</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> charge</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(cartId);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">using</code> غير مسموحة في الدوال <code dir=\"ltr\">async</code>.","why":"إنها مسموحة؛ وللتنظيف غير المتزامن ستستخدم <code dir=\"ltr\">await using</code>، لكن هذه ليست المشكلة هنا."},{"text":"يجب أن تكون <code dir=\"ltr\">await using</code>، لأن الدالة <code dir=\"ltr\">async</code>.","why":"<code dir=\"ltr\">await using</code> للموارد ذات التحرير غير المتزامن؛ والمشكلة الحقيقية في نطاق القفل."},{"text":"القفل لا يُحرَّر أبدًا.","why":"إنه يُحرَّر، لكن مبكرًا جدًا."},{"text":"يُحرَّر القفل عند نهاية كتلة <code dir=\"ltr\">if</code>، قبل أن تُنفَّذ <code dir=\"ltr\">charge</code>.","why":"صحيح. <code dir=\"ltr\">using</code> محصورة في كتلتها؛ أعلنها في الكتلة التي تحتوي استدعاء <code dir=\"ltr\">charge</code> أيضًا."}],"answer":3},{"q":"<p>يقع <code dir=\"ltr\">interface Window { dataLayer: unknown[] }</code> في المستوى الأعلى من <code dir=\"ltr\">src/analytics.ts</code>، وفيه imports أيضًا. وما زال <code dir=\"ltr\">window.dataLayer</code> خطأً. لماذا؟</p>","options":[{"text":"في ملف وحدة، يكون الـ interface في المستوى الأعلى محلّيًا لتلك الوحدة؛ غلّفه بـ <code dir=\"ltr\">declare global { … }</code> ليندمج مع <code dir=\"ltr\">Window</code> العام.","why":"صحيح. الملفات التي فيها imports أو exports وحدات، ولا يصل إلى النطاق العام من داخل إحداها إلا <code dir=\"ltr\">declare global</code>."},{"text":"<code dir=\"ltr\">Window</code> نوع مدمج ولا يمكن توسيعه.","why":"يمكن ذلك؛ توسيع <code dir=\"ltr\">Window</code> بدمج التصريحات أمر شائع."},{"text":"يجب أن يكون اسمًا مستعارًا بـ <code dir=\"ltr\">type</code> بدل interface.","why":"الأسماء المستعارة للأنواع لا تندمج أبدًا، فلن يوسّع <code dir=\"ltr\">type</code> النوع <code dir=\"ltr\">Window</code> أيضًا."},{"text":"دمج الـ interfaces لا يعمل إلا في ملفات <code dir=\"ltr\">.d.ts</code>.","why":"الدمج يعمل في ملفات <code dir=\"ltr\">.ts</code> أيضًا؛ المهم هو ما إذا كان التصريح في النطاق العام."}],"answer":0},{"q":"<p>مستودع أحادي (monorepo) فيه ست حزم تُفحص أنواعها كبرنامج واحد كبير، وكل تغيير صغير يعيد فحصها كلها في 90 ثانية. أيّ تغيير يساعد أكثر؟</p>","options":[{"text":"أطفئ <code dir=\"ltr\">strict</code> في الحزمة الأبطأ.","why":"هذا يقلّل جودة الفحص، ونادرًا ما يكون <code dir=\"ltr\">strict</code> هو الكلفة الرئيسية."},{"text":"قسّمه إلى مراجع مشاريع (<code dir=\"ltr\">composite: true</code> لكل حزمة، و<code dir=\"ltr\">tsc -b</code> في الجذر)، فلا يُعاد فحص الحزم التي لم تتغيّر.","why":"صحيح. تُبنى كل حزمة مرة واحدة وتُعاد استخدام تصريحاتها، فلا يُعيد التغيير إلا فحص ما يعتمد عليه."},{"text":"اضبط <code dir=\"ltr\">skipLibCheck: false</code> لالتقاط مزيد من المشكلات مبكرًا.","why":"هذا يجعل الفحص أبطأ، لا أسرع."},{"text":"ادمج كل الحزم في مجلد <code dir=\"ltr\">src</code> واحد.","why":"برنامج واحد أكبر فيه المشكلة نفسها مع حدود أقل للتخزين المؤقت."}],"answer":1},{"q":"<p>ملف <code dir=\"ltr\">.js</code> يبدأ بـ <code dir=\"ltr\">// @ts-check</code> ويعلن <code dir=\"ltr\">/** @param {Order} order */ function ship(order) { … }</code>. ماذا يفعل TypeScript به (مع تفعيل <code dir=\"ltr\">allowJs</code>)؟</p>","options":[{"text":"لا شيء، حتى يُعاد تسمية الملف إلى <code dir=\"ltr\">.ts</code>.","why":"التعليق يُدخل ملف JavaScript في الفحص دون إعادة تسميته."},{"text":"يفحص الملف فقط إن كان <code dir=\"ltr\">checkJs</code> أيضًا <code dir=\"ltr\">true</code> في tsconfig.","why":"<code dir=\"ltr\">checkJs</code> يفعّل الفحص لكل ملفات JS؛ و<code dir=\"ltr\">// @ts-check</code> تفعله لملف واحد بغضّ النظر عنه."},{"text":"يفحص تعليقات JSDoc فقط، لا الكود.","why":"JSDoc يوفّر الأنواع؛ والكود هو ما يُفحص مقابلها."},{"text":"يفحص أنواع الملف كله، مستخدمًا تعليقات JSDoc كأنواع لـ <code dir=\"ltr\">ship</code> ومعاملها.","why":"صحيح. هذا يتيح لك فحصًا حقيقيًا على ملفات JavaScript الخطرة قبل تحويلها."}],"answer":3}]},"final":[{"q":"<p>أيّ زوج من التغييرات يجعل <code dir=\"ltr\">cancelOrder(customer.id)</code> و<code dir=\"ltr\">add(usdPrice, eurShipping)</code> كليهما خطأ ترجمة؟</p>","options":[{"text":"سِم <code dir=\"ltr\">OrderId</code> و<code dir=\"ltr\">CustomerId</code>، وحدّد نوع <code dir=\"ltr\">add</code> بـ <code dir=\"ltr\">add&lt;C&gt;(a: Money&lt;C&gt;, b: Money&lt;NoInfer&lt;C&gt;&gt;)</code>.","why":"صحيح. الوسوم تجعل المعرّفات المتشابهة في الشكل متمايزة، و<code dir=\"ltr\">NoInfer</code> تمنع استنتاج union العملات."},{"text":"استخدم unions حرفية للحالات و<code dir=\"ltr\">satisfies</code> على كائنات الإعداد.","why":"كلتاهما عادة جيدة، لكن لا أحد منهما يميّز بين معرّفين رقميين أو عملتين."},{"text":"فعّل <code dir=\"ltr\">exactOptionalPropertyTypes</code> و<code dir=\"ltr\">noUncheckedIndexedAccess</code>.","why":"هذان الخياران يفحصان الخصائص الاختيارية والوصول بالفهرس، لا المعرّفات ولا العملات."},{"text":"أعطِ <code dir=\"ltr\">add</code> و<code dir=\"ltr\">cancelOrder</code> معاملات نوع <code dir=\"ltr\">const</code>.","why":"<code dir=\"ltr\">const</code> تحتفظ بالقيم الحرفية في الاستنتاج؛ لا تجعل المعرّفات أو العملات غير متوافقة."}],"answer":0},{"q":"<p>ما نوع <code dir=\"ltr\">summary</code>؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"11\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> pick</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#953800;--shiki-dark:#FFA657\">T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">K</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> extends</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> keyof</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">obj</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">...</span><span style=\"color:#953800;--shiki-dark:#FFA657\">keys</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> K</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">[])</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Pick</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#953800;--shiki-dark:#FFA657\">T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">K</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> { </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* … */</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> summary</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> pick</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(order, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'id'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'status'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">Partial&lt;Order&gt;</code>","why":"<code dir=\"ltr\">Pick</code> تُبقي الخصائص المختارة إلزامية؛ لا شيء هنا يجعلها اختيارية."},{"text":"<code dir=\"ltr\">Order</code>","why":"لا يُحتفظ إلا بالمفاتيح التي تمرّرها، فليس <code dir=\"ltr\">Order</code> الكامل هو النتيجة."},{"text":"<code dir=\"ltr\">Pick&lt;Order, keyof Order&gt;</code>","why":"يُستنتج <code dir=\"ltr\">K</code> من الوسائط، ولا يتّسع إلى كل المفاتيح."},{"text":"<code dir=\"ltr\">Pick&lt;Order, 'id' | 'status'&gt;</code>","why":"صحيح. كل وسيط بقية موقع استنتاج لـ <code dir=\"ltr\">K</code>، والقيد <code dir=\"ltr\">keyof T</code> يحتفظ بالقيم الحرفية."}],"answer":3},{"q":"<p>سلة محفوظة لعميل في <code dir=\"ltr\">localStorage</code> كتبها إصدار العام الماضي من التطبيق، بشكل مختلف. ما الطريقة الصحيحة لتحميلها؟</p>","options":[{"text":"<code dir=\"ltr\">JSON.parse(saved) as Cart</code>","why":"التحويل يثق ببيانات العام الماضي ثقة عمياء؛ ويظهر عدم التطابق لاحقًا كانهيارات."},{"text":"استخدم <code dir=\"ltr\">JSON.parse(saved)</code> مباشرة، لأن نوعها <code dir=\"ltr\">any</code>.","why":"<code dir=\"ltr\">any</code> تنشر الشكل الخاطئ في التطبيق بصمت."},{"text":"حلّلها كـ <code dir=\"ltr\">unknown</code> إلى <code dir=\"ltr\">Result</code>، وارجع إلى سلة فارغة (أو رحّلها) حين يفشل التحليل.","why":"صحيح. البيانات القديمة حالة متوقَّعة، فتصبح إخفاقًا مُعالَجًا عند الحدود."},{"text":"استدعِ دالة تأكيد أثناء الـ render ودع حدّ الأخطاء يعرض شاشة انهيار.","why":"التخزين القديم متوقَّع لا خطأ برمجي، فإسقاط الصفحة هو الاستجابة الخاطئة."}],"answer":2},{"q":"<p>ما هو <code dir=\"ltr\">NoNulls&lt;{ coupon: string | null; note?: string }&gt;</code>؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"12\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">type</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> NoNulls</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#953800;--shiki-dark:#FFA657\">T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { [</span><span style=\"color:#953800;--shiki-dark:#FFA657\">K</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> in</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> keyof</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> NonNullable</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#953800;--shiki-dark:#FFA657\">T</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">[</span><span style=\"color:#953800;--shiki-dark:#FFA657\">K</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]> };</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">{ coupon: string | null; note: string }</code>","why":"<code dir=\"ltr\">NonNullable</code> تُزيل <code dir=\"ltr\">null</code> من <code dir=\"ltr\">coupon</code>، والتحويل التماثلي يُبقي <code dir=\"ltr\">note</code> اختيارية."},{"text":"<code dir=\"ltr\">{ coupon: string; note?: string }</code>","why":"صحيح. تُزال <code dir=\"ltr\">null</code> من نوع كل خاصية، ويُنسخ المعدِّل <code dir=\"ltr\">?</code> من الأصل."},{"text":"<code dir=\"ltr\">{ coupon: string; note: string }</code>","why":"التحويل تماثليّ الشكل، فينسخ معدِّل الاختيارية في <code dir=\"ltr\">note</code>؛ ولا يُزيله إلا <code dir=\"ltr\">-?</code>."},{"text":"<code dir=\"ltr\">never</code>","why":"الـ mapped types على نوع كائن تنتج نوع كائن، لا <code dir=\"ltr\">never</code>."}],"answer":1},{"q":"<p>يضيف فريق المدفوعات <code dir=\"ltr\">'requires-3ds'</code> إلى الـ union المسمّى <code dir=\"ltr\">PaymentError</code>. الدالة <code dir=\"ltr\">errorMessage(e: PaymentError): string</code> تتفرّع على <code dir=\"ltr\">e.type</code> دون <code dir=\"ltr\">default</code>. ماذا يحدث؟</p>","options":[{"text":"تفشل <code dir=\"ltr\">errorMessage</code> في الترجمة حتى تُضاف حالة <code dir=\"ltr\">'requires-3ds'</code>.","why":"صحيح. مع العضو الجديد غير المُعالَج، تصبح نهاية الدالة قابلة للوصول، ونوع الإرجاع <code dir=\"ltr\">string</code> يرفض ذلك."},{"text":"تمرّ في الترجمة وتُعيد <code dir=\"ltr\">undefined</code> مع الخطأ الجديد.","why":"نوع الإرجاع الصريح <code dir=\"ltr\">: string</code> هو بالضبط ما يمنع ذلك من المرور في الترجمة."},{"text":"تمرّ في الترجمة وترمي خطأً وقت التشغيل مع الخطأ الجديد.","why":"لا شيء يرمي خطأً؛ الـ compiler يوقف الكود قبل أن يُنفَّذ."},{"text":"لا شيء يتغيّر، لأن الـ unions لا تُفحص إلا وقت التشغيل.","why":"الـ unions أنواع وقت الترجمة، والشمول يُفحص وقت الترجمة."}],"answer":0},{"q":"<p>أيّ نص قابل للإسناد إلى <code dir=\"ltr\">type OrderPath = `/orders/${number}`</code>؟</p>","options":[{"text":"<code dir=\"ltr\">'/orders/abc'</code>","why":"<code dir=\"ltr\">abc</code> ليس نصًا رقميًا، فلا يطابق العنصر النائب <code dir=\"ltr\">${number}</code>."},{"text":"<code dir=\"ltr\">'/orders/'</code>","why":"النص الفارغ ليس رقمًا، فلا يجد العنصر النائب ما يطابقه."},{"text":"<code dir=\"ltr\">'/orders/1042/lines'</code>","why":"يجب أن يطابق العنصر النائب بقية النص، و<code dir=\"ltr\">1042/lines</code> ليس رقمًا."},{"text":"<code dir=\"ltr\">'/orders/1042'</code>","why":"صحيح. <code dir=\"ltr\">1042</code> نص رقمي، وهذا بالضبط ما تقبله <code dir=\"ltr\">${number}</code>."}],"answer":3},{"q":"<p>بعد تفعيل <code dir=\"ltr\">noUncheckedIndexedAccess</code>، أيّ سطر يصبح خطأ ترجمة (مع <code dir=\"ltr\">lines: Line[]</code>)؟</p>","options":[{"text":"<code dir=\"ltr\">for (const line of lines) console.log(line.sku);</code>","why":"التكرار بـ <code dir=\"ltr\">for…of</code> يعطي عناصر فعلية، فلا يضيف الخيار <code dir=\"ltr\">undefined</code>."},{"text":"<code dir=\"ltr\">lines.map((line) =&gt; line.sku);</code>","why":"دوال المصفوفات تمرّر عناصر حقيقية إلى الـ callback، فلا تتأثّر."},{"text":"<code dir=\"ltr\">const [first] = lines; console.log(first.sku);</code>","why":"صحيح. التفكيك حسب الموضع وصولٌ بالفهرس، فيكون <code dir=\"ltr\">first</code> من نوع <code dir=\"ltr\">Line | undefined</code> مع الخيار."},{"text":"<code dir=\"ltr\">console.log(lines.length);</code>","why":"<code dir=\"ltr\">length</code> رقم دائمًا؛ الخيار يؤثّر فقط في البحث عن العناصر والمفاتيح."}],"answer":2},{"q":"<p>زُخرفت <code dir=\"ltr\">charge</code> بـ <code dir=\"ltr\">@retry(3)</code> في السطر الذي فوق <code dir=\"ltr\">@logged</code>. تفشل البوابة مرتين ثم تنجح. كم سطر تسجيل تطبع <code dir=\"ltr\">logged</code> لاستدعاء واحد؟</p>","options":[{"text":"1، لأن <code dir=\"ltr\">logged</code> تغلّف الاستدعاء كله مع إعادة المحاولة","why":"هذا سيكون الترتيب لو كُتبت <code dir=\"ltr\">@logged</code> فوق <code dir=\"ltr\">@retry(3)</code>. الـ decorators تُطبَّق من الأسفل إلى الأعلى."},{"text":"3، لأن <code dir=\"ltr\">logged</code> تُطبَّق أولًا و<code dir=\"ltr\">retry</code> تستدعي الـ method المسجِّلة في كل محاولة","why":"صحيح. الـ decorator الأقرب إلى الـ method يغلّفها أولًا، فتمرّ كل إعادة محاولة عبر غلاف التسجيل."},{"text":"0، لأن decoratorين على method واحدة يلغي أحدهما الآخر","why":"الـ decorators المكدّسة تتركّب؛ لا تلغي بعضها أبدًا."},{"text":"6، لأن كل decorator يسجّل مرة لكل محاولة","why":"<code dir=\"ltr\">logged</code> وحدها تسجّل؛ و<code dir=\"ltr\">retry</code> تستدعي الـ method المغلَّفة مرة أخرى فقط."}],"answer":1},{"q":"<p>لماذا يمكن تمرير <code dir=\"ltr\">DetailedOrder</code> (<code dir=\"ltr\">id</code> و<code dir=\"ltr\">status</code> و<code dir=\"ltr\">totalCents</code> و<code dir=\"ltr\">customer</code>) حيث يُنتظر <code dir=\"ltr\">Order</code> (<code dir=\"ltr\">id</code> و<code dir=\"ltr\">status</code> و<code dir=\"ltr\">totalCents</code>)، والعكس غير ممكن؟</p>","options":[{"text":"كل <code dir=\"ltr\">DetailedOrder</code> يملك كل الخصائص التي يتطلّبها <code dir=\"ltr\">Order</code>، فهو ينتمي إلى مجموعة القيم الأصغر؛ أما <code dir=\"ltr\">Order</code> فقد يفتقد <code dir=\"ltr\">customer</code>.","why":"صحيح. قابلية الإسناد هي علاقة الاحتواء، وخصائص إلزامية أكثر تعني مجموعة أصغر."},{"text":"لأن <code dir=\"ltr\">DetailedOrder</code> أُعلن بـ <code dir=\"ltr\">extends Order</code>.","why":"التصريحات لا تهمّ في نظام أنواع بنيوي؛ الأشكال وحدها تهمّ."},{"text":"لأن أسماء الأنواع تُقارن أبجديًا.","why":"TypeScript لا يقارن الأسماء أبدًا؛ إنه يقارن البنية."},{"text":"لأن <code dir=\"ltr\">Order</code> هو interface والـ interfaces لا تقبل إلا الأنواع الفرعية.","why":"الـ interfaces والأسماء المستعارة للأنواع تتبع القواعد البنيوية نفسها هنا."}],"answer":0},{"q":"<p>أيّ توقيع هو تحويل غير مفحوص متنكّر؟</p>","options":[{"text":"<code dir=\"ltr\">function sortByTotal&lt;T extends { totalCents: number }&gt;(orders: T[]): T[]</code>","why":"<code dir=\"ltr\">T</code> يربط المدخل بالمخرج، فيكون نوع النتيجة بالضبط ما مُرِّر."},{"text":"<code dir=\"ltr\">function call&lt;R extends keyof Routes&gt;(route: R): Routes[R]['output']</code>","why":"يُستنتج <code dir=\"ltr\">R</code> من وسيط المسار، فتنبع النتيجة مما كتبه المستدعي."},{"text":"<code dir=\"ltr\">function indexById&lt;T extends { id: number }&gt;(items: T[]): Map&lt;number, T&gt;</code>","why":"<code dir=\"ltr\">T</code> يظهر في المدخل والمخرج، رابطًا بينهما."},{"text":"<code dir=\"ltr\">function readSetting&lt;T&gt;(key: string): T</code>","why":"صحيح. <code dir=\"ltr\">T</code> لا يظهر إلا في نوع الإرجاع، فيستطيع المستدعي اختيار أي نوع ولا شيء يفحصه."}],"answer":3},{"q":"<p>ماذا يفعل <code dir=\"ltr\">declare module 'legacy-shipping-calc';</code> دون جسم؟</p>","options":[{"text":"يثبّت حزمة <code dir=\"ltr\">@types</code> المطابقة.","why":"التصريحات لا تثبّت شيئًا أبدًا؛ إنها تصف الكود للـ compiler فقط."},{"text":"يولّد الأنواع بقراءة JavaScript الخاصة بالحزمة.","why":"لا يستنتج TypeScript أنواعًا لحزمة من تصريح وحدة مختصر."},{"text":"يجعل الـ import يمرّ في الترجمة، فيكون نوع كل ما يُستورد من الحزمة <code dir=\"ltr\">any</code>.","why":"صحيح. إنه مخرج طوارئ للترحيل، لا بديل عن التصريحات الحقيقية."},{"text":"يسبّب خطأ ترجمة حتى يُملأ الجسم.","why":"الصيغة المختصرة صالحة بذاتها؛ ولهذا يسهل نسيان وجودها."}],"answer":2},{"q":"<p>أيّ ملف يجب أن تحوّله إلى TypeScript أولًا في عملية ترحيل؟</p>","options":[{"text":"<code dir=\"ltr\">checkoutPage.js</code>، نقطة الدخول التي تستورد 30 وحدة أخرى","why":"إن حُوّل أولًا فسيستورد كودًا بلا أنواع وينتهي ممتلئًا بـ <code dir=\"ltr\">any</code>."},{"text":"<code dir=\"ltr\">money.js</code>، الذي يستورده 40 ملفًا ولا يستورد شيئًا داخليًا","why":"صحيح. إنه ورقة، فيمكن تحديد أنواعه بالكامل اليوم، ويستفيد فورًا كل ملف يستورده."},{"text":"أكبر ملف في المستودع، للتخلّص منه","why":"الحجم لا يقول شيئًا عن الاعتماديات؛ والملف الكبير الذي يستورد كودًا بلا أنواع يكسب القليل."},{"text":"آخر ملف تغيّر","why":"الحداثة لا تخبرك إن كانت اعتمادياته قد حُدّدت أنواعها بعد."}],"answer":1}],"glossary":[{"id":"structural-typing","term":"التنميط البنيوي (Structural typing)","definition":"قاعدة TypeScript التي تجعل القيمة متوافقة مع نوع ما حين تملك الشكل المطلوب، أيًّا كان اسم ذلك النوع. فالنوعان المختلفان في الاسم المتطابقان في الخصائص قابلان للتبادل.","lesson":"l-at-1-2"},{"id":"assignability","term":"قابلية الإسناد (Assignability)","definition":"إمكانية استخدام قيمة من نوع ما حيث يُنتظر نوع آخر. تعمل مثل علاقة الاحتواء بين المجموعات: المجموعة الأضيق من القيم تقع داخل المجموعة الأوسع.","lesson":"l-at-1-2"},{"id":"excess-property-check","term":"فحص الخصائص الزائدة (Excess property check)","definition":"فحص يعلّم الخصائص المجهولة في كائن حرفي طازج مكتوب مباشرة حيث يُنتظر نوع. يلتقط الأخطاء الإملائية، لكن القيم الممرَّرة عبر متغيّر تتخطّاه.","lesson":"l-at-1-2"},{"id":"control-flow-analysis","term":"تحليل تدفّق التحكّم (Control-flow analysis)","definition":"طريقة TypeScript في تتبّع نوع المتغيّر عبر الفروع وجمل العودة والإسنادات، بحيث يكون للاسم نفسه نوع أضيق بعد الفحص مما كان عليه قبله.","lesson":"l-at-1-3"},{"id":"narrowing","term":"Narrowing","definition":"تضييق نوع واسع إلى نوع أكثر تحديدًا بفحص وقت التشغيل، مثل <code dir=\"ltr\">typeof</code> أو <code dir=\"ltr\">===</code> أو <code dir=\"ltr\">in</code> أو <code dir=\"ltr\">instanceof</code> أو type predicate.","lesson":"l-at-1-3"},{"id":"discriminated-union","term":"Discriminated union","definition":"union من أنواع كائنات تتشارك خاصية بقيمة حرفية مختلفة في كل عضو، مثل <code dir=\"ltr\">status</code>. وفحص تلك الخاصية يضيّق الكائن كله إلى عضو واحد.","lesson":"l-at-1-4"},{"id":"const-assertion","term":"as const","definition":"تأكيد const يستنتج أضيق نوع ممكن للقيمة: القيم الحرفية تبقى حرفية، والمصفوفات تصبح tuples للقراءة فقط، والخصائص تصبح للقراءة فقط.","lesson":"l-at-1-5"},{"id":"satisfies","term":"satisfies","definition":"عامل (operator) يفحص قيمة مقابل نوع دون أن يستبدل النوع المستنتَج للقيمة، فتحصل على التحقّق وتحتفظ في الوقت نفسه بالمفاتيح والقيم الحرفية الدقيقة.","lesson":"l-at-1-5"},{"id":"type-parameter","term":"معامل النوع (Type parameter)","definition":"نوع نائب في دالة أو نوع generic، مثل <code dir=\"ltr\">T</code>، يربط المدخلات بالمخرجات. ويجب أن يظهر مرتين على الأقل كي يضيف أمانًا حقيقيًا في الأنواع.","lesson":"l-at-2-1"},{"id":"generic-constraint","term":"قيد الـ generic (Generic constraint)","definition":"جملة <code dir=\"ltr\">extends</code> على معامل نوع تحدّ من الأنواع التي يقبلها، مثل <code dir=\"ltr\">T extends { id: number }</code>، وتجعل تلك الخصائص قابلة للاستخدام داخل الدالة أيضًا.","lesson":"l-at-2-1"},{"id":"inference-site","term":"موقع الاستنتاج (Inference site)","definition":"موضع في نوع معامل يظهر فيه معامل نوع. عند الاستدعاء، يجمع TypeScript مرشّحًا من كل موقع ليقرّر ما هو معامل النوع.","lesson":"l-at-2-2"},{"id":"const-type-parameter","term":"معامل النوع const (const type parameter)","definition":"معامل نوع معرَّف بـ <code dir=\"ltr\">const</code> (منذ TypeScript 5.0)، يستنتج الوسائط كأن المستدعي كتب <code dir=\"ltr\">as const</code>، فيحتفظ بالقيم الحرفية والـ tuples للقراءة فقط.","lesson":"l-at-2-2"},{"id":"noinfer","term":"NoInfer","definition":"نوع مدمج (منذ TypeScript 5.4) يجعل موضعًا ما للفحص فقط، فيُتحقَّق منه مقابل معامل نوع لكنه لا يساهم أبدًا بمرشّح في الاستنتاج.","lesson":"l-at-2-3"},{"id":"indexed-access-type","term":"نوع الوصول بالفهرس (Indexed access type)","definition":"نوع مثل <code dir=\"ltr\">Order['status']</code> أو <code dir=\"ltr\">T[number]</code> يبحث عن نوع خاصية ما، أو عن نوع عناصر مصفوفة، باستخدام صياغة الأقواس المربّعة.","lesson":"l-at-3-1"},{"id":"mapped-type","term":"Mapped type","definition":"نوع يمرّ على union من المفاتيح ويبني خاصية واحدة لكل مفتاح، كما في <code dir=\"ltr\">{ [K in keyof T]?: T[K] }</code>، وهو تعريف <code dir=\"ltr\">Partial</code>.","lesson":"l-at-3-2"},{"id":"key-remapping","term":"إعادة تسمية المفاتيح (Key remapping)","definition":"جملة <code dir=\"ltr\">as</code> في mapped type تعيد تسمية كل مفتاح، غالبًا بـ template literal. وتحويل مفتاح إلى <code dir=\"ltr\">never</code> يحذفه، وهكذا يعمل <code dir=\"ltr\">Omit</code>.","lesson":"l-at-3-2"},{"id":"conditional-type","term":"Conditional type","definition":"نوع بالشكل <code dir=\"ltr\">T extends U ? X : Y</code> يختار بين نوعين بحسب ما إذا كان <code dir=\"ltr\">T</code> قابلًا للإسناد إلى <code dir=\"ltr\">U</code>، ويُسمّى أيضًا النوع الشرطي.","lesson":"l-at-3-3"},{"id":"distributive-conditional-type","term":"النوع الشرطي التوزيعي (Distributive conditional type)","definition":"conditional type يكون النوع المفحوص فيه معامل نوع مجرّدًا. حين يُعطى union يُنفَّذ مرة لكل عضو ويجمع النتائج؛ وتغليف الطرفين بأقواس مربّعة يوقف ذلك.","lesson":"l-at-3-3"},{"id":"infer","term":"infer","definition":"كلمة مفتاحية تُستخدم داخل جملة <code dir=\"ltr\">extends</code> في conditional type لالتقاط جزء من النوع المطابق، كما في <code dir=\"ltr\">ReturnType</code> الذي يلتقط نوع إرجاع الدالة.","lesson":"l-at-3-3"},{"id":"template-literal-type","term":"Template literal type","definition":"نوع نصي يُبنى بصياغة علامات الاقتباس المائلة من أنواع أخرى، مثل <code dir=\"ltr\">`order.${OrderStatus}`</code>. والـ unions داخله تتوسّع إلى كل التركيبات الممكنة.","lesson":"l-at-3-4"},{"id":"branded-type","term":"Branded type","definition":"تقاطع (intersection) بين نوع أولي وخاصية لا وجود لها إلا في نظام الأنواع، مثل <code dir=\"ltr\">number &amp; { readonly [brand]: 'OrderId' }</code>، فتتوقّف القيم ذات النوع نفسه وقت التشغيل عن التبادل.","lesson":"l-at-4-1"},{"id":"smart-constructor","term":"المُنشئ الذكي (Smart constructor)","definition":"دالة تتحقّق من قيمة خام ثم تُعيدها كـ branded type. وهي المكان الوحيد الذي يجب أن يظهر فيه تحويل إلى ذلك الوسم.","lesson":"l-at-4-1"},{"id":"exhaustiveness-check","term":"فحص الشمول (Exhaustiveness check)","definition":"ضمانة وقت الترجمة بأن كل عضو في union قد عولج، وتتحقّق عادةً بتمرير القيمة المتبقّية إلى معامل من نوع <code dir=\"ltr\">never</code> في فرع <code dir=\"ltr\">default</code>.","lesson":"l-at-4-1"},{"id":"result-type","term":"نوع Result (Result type)","definition":"discriminated union مثل <code dir=\"ltr\">{ ok: true; value: T } | { ok: false; error: E }</code> يُعيد الإخفاقات المتوقَّعة كقيم، فيُضطر المستدعون إلى معالجتها بدل نسيانها.","lesson":"l-at-4-2"},{"id":"type-predicate","term":"Type predicate","definition":"نوع إرجاع دالة بالشكل <code dir=\"ltr\">value is T</code>. حين تُعيد الدالة true يضيق الوسيط إلى <code dir=\"ltr\">T</code> في موضع الاستدعاء؛ أما جسم الدالة نفسه فلا يُتحقَّق منه.","lesson":"l-at-4-3"},{"id":"assertion-function","term":"دالة التأكيد (Assertion function)","definition":"دالة نوع إرجاعها <code dir=\"ltr\">asserts value is T</code>. ترمي خطأً حين يفشل الفحص، وحين تعود بشكل طبيعي تضيّق القيمة لبقية النطاق.","lesson":"l-at-4-3"},{"id":"using-declaration","term":"تصريح using (using declaration)","definition":"تصريح يستدعي <code dir=\"ltr\">[Symbol.dispose]()</code> على القيمة حين تنتهي كتلته، بالعودة أو بالرمي، ويحرّر الموارد المتعددة بترتيب معكوس لترتيب تصريحها.","lesson":"l-at-5-2"},{"id":"declaration-merging","term":"دمج التصريحات (Declaration merging)","definition":"القاعدة التي تجعل عدة تصريحات بالاسم نفسه، مثل تصريحَي interface، تتّحد في تصريح واحد. وهي طريقة توسيع أنواع الـ lib والـ interfaces الخاصة بالمكتبات.","lesson":"l-at-5-3"},{"id":"module-augmentation","term":"توسيع الوحدات (Module augmentation)","definition":"الإضافة إلى الأنواع داخل وحدة باستخدام <code dir=\"ltr\">declare module 'name' { … }</code> من ملف هو نفسه وحدة، مثلًا لتوسيع interface في مكتبة ما.","lesson":"l-at-5-3"},{"id":"project-references","term":"مراجع المشاريع (Project references)","definition":"ميزة في tsconfig تقسم قاعدة الكود إلى مشاريع تُبنى منفصلة (<code dir=\"ltr\">composite: true</code>، وتُبنى بـ <code dir=\"ltr\">tsc -b</code>)، فلا يُعاد فحص الأجزاء التي لم تتغيّر.","lesson":"l-at-5-4"}]}