in / out التغاير والتباين
آخر تحديث: 2026-10-22
in / out التغاير والتباين
تصف التغايرية «كيف يؤثر معامل النوع داخل النوع المركب على التوافق الكلي»: قيم الإرجاع متغايرة (يمكن أن يحل النوع الفرعي محل)، والمعاملات متباينة (الدالة التي تقبل النوع الأب يمكن أن تحل محلها). توافق إسناد الدوال والتوافق المتداخل للمصفوفات/الواجهات كله يحدده هذا — وفهمه يجيب بشكل منهجي على «لماذا يخطئ هذا الإسناد أو لا يخطئ».
| المجموعة | الأنواع العامة |
|---|---|
| النوع | بناء الجملة |
| الوضع الصارم | غير مطلوب |
ℹ️ معلومة يحوّل المحرر لغة TypeScript إلى JavaScript ثم يشغّلها (بدون فحص أنواع)؛ راجع ناتج كل مثال لنتيجة فحص الأنواع.
📝 الصيغة
// من TS 4.7 فصاعدا يمكن التصريح بالتغاير صراحةً (يُستنتج بنيويًا افتراضيًا)
interface Producer<out T> { produce(): T; } // تغاير طرد: ينتج T فقط
interface Consumer<in T> { consume(v: T): void; } // تغاير عكسي: يستهلك T فقط
// القواعد الطبيعية لإسناد الدوال
let handleDog: (d: Dog) => void = handleAnimal; // OK: تغاير عكسي في المعامل
const adoptAnimal: (tag: string) => Animal = adoptDog; // OK: تغاير طرد في الإرجاع
⚙️ المعاملات
| <out T> | يظهر T فقط في مواضع الإخراج (قيم الإرجاع): Producer<Dog> يمكن استخدامها كـ Producer<Animal> |
|---|---|
| <in T> | يظهر T فقط في مواضع الإدخال (المعاملات): Consumer<Animal> يمكن استخدامها كـ Consumer<Dog> |
| <in out T> | القراءة والكتابة كلاهما مكشوف: يشترط تطابقًا صارمًا في النوع وإلا كان غير متوافق |
القيمة المُعادة:التغايرية قاعدة توافق أنواع ولا تنتج كود تشغيل؛ فما تحدده هو «من يمكن إسناده إلى من».
▶ مثال
عدّل الكود أدناه واضغط «جرّب» لرؤية نتيجة التحويل:
الناتج:
Rex eats food
Rex-A1 eats food
(مخرجات التشغيل بعد التحويل؛ العكس لا يصح — إسناد دالة تعالج Dog فقط إلى موضع (a: Animal) => void سيرفضه المترجم، وهذا بالضبط تباين المعاملات يحجب إسنادًا غير آمن)
💡 نقاط مهمة
ℹ️ معلومة ذاكرة بالحدس: «الإنتاج يمكن أن يكون أكثر تحديدًا (تغاير)، والاستهلاك يمكن أن يكون أوسع (تباين)» — فمالك الحيوان الأليف الذي يقبل أي Animal يستطيع بالطبع رعاية Dog، وحقل الكلاب الذي يُنتج Dog يستطيع بالطبع تلبية أي طلب Animal.
⚠️ تنبيه المصفوفات القابلة للتعديل تُنتج وتستهلك معًا (متغايرة ثنائية)، وهي المنطقة الحمراء للإسنادات غير الآمنة؛ فعند تصميم واجهة عامة فكّر أولًا: هل T يدخل أم يخرج، ثم ضع علامة in/out.
💡 تلميح التعليقات الصريحة في TS 4.7 غالبًا لأغراض التوثيق والتسريع: الاستدلال البنيوي صحيح في الغالب، لكن وضع علامة in/out يجعل الفحص النوعي العميق أسرع والنية أوضح ورسائل الخطأ أكثر مباشرة.
🏷️ الأنواع العامة ذات صلة
💡 حالات ذات صلة
المزيد من الحالات قادم قريبًا.
📚 دروس ذات صلة
❓ أسئلة شائعة
س كيف تميّز بين التغاير والتباين في جملة واحدة؟
ج انظر أين يظهر معامل النوع: مواضع الإخراج (قيم الإرجاع) تغايرية — يبقى النوع الفرعي متوافقًا ككل؛ ومواضع الإدخال (المعاملات) تباينية — يبقى النوع الأب متوافقًا ككل. وإذا كان إدخالًا وإخراجًا معًا فهو ثابت (تطابق صارم في النوع).
س لماذا معاملات الدوال تباينية لا تغايرية؟
ج يوضح المثال المعاكس: إذا كان يمكن إسناد (d: Dog) => void إلى (a: Animal) => void لانفجر كل شيء عند تمرير المستدعي Cat. بينما إسناد (a: Animal) => void إلى (d: Dog) => void آمن — فهو يعالج أي Animal وDog بالطبع ضمنها.
س متى تحتاج إلى كتابة تعليقات in/out يدويًا؟
ج عندما تكون مواضع معاملات النوع معقدة، أو يكون الاستدلال البنيوي بطيئًا، أو تكون النتيجة معاكسة للحدس (مثل مُرسِل الأحداث emitter أو واجهات متداخلة بعمق). أما كود الأعمال اليومي فيمكنه الاعتماد على الاستدلال البنيوي الافتراضي دون تعليق في كل مكان.