نوع children في React و TypeScript: دليل شامل

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

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

ابدأ الدورة

ما الذي يخفيه prop children في React و TypeScript؟

\n\n

إذا سبق لك كتابة مكون (Component) في React باستخدام TypeScript، فمن المحتمل أنك واجهت السؤال: "ما هو نوع البيانات الخاص بـ prop children؟". هذا السؤال هو من أكثر الأسئلة شيوعًا على Stack Overflow، وليس بدون سبب. للوهلة الأولى، يبدو أن الإجابة بسيطة: ReactNode. ولكن الشيطان، كما يُقال، يكمن في التفاصيل.

\n\n

في هذه المقالة، لن نقدم إجابة جافة فقط. سنشرح جميع الأنواع الممكنة لـ children، والاختلافات بينها، وأفضل الممارسات، والمزالق المحتملة. ستتعرف متى تستخدم ReactNode، ومتى تستخدم ReactElement، ومتى تستخدم أنواعًا أكثر تحديدًا. هيا بنا!

\n\n

لماذا هذا السؤال شائع جدًا؟

\n\n

المشكلة هي أن children هو prop خاص في React. يمكن أن يكون أي شيء:

\n\n
    \n
  • نصًا: "مرحبًا بالعالم!"
  • \n
  • رقمًا: {42}
  • \n
  • عنصر JSX: <div>...</div>
  • \n
  • مصفوفة من العناصر: [<span/>, <span/>]
  • \n
  • دالة (render prop): {() => <div/>}
  • \n
  • حتى null أو undefined أو boolean
  • \n
\n\n

بسبب هذه المرونة، غالبًا ما يكتب المبتدئون children: any، مما يلغي فائدة TypeScript بأكملها. دعنا نفهم الأساليب الصحيحة.

\n\n

الأنواع الرئيسية لـ children

\n\n

1. ReactNode — الحل الشامل

\n\n

هذا هو النوع الأكثر شيوعًا وصحة لـ children في 90% من الحالات. يشمل كل ما يمكن لـ React عرضه.

\n\n
import { ReactNode } from 'react';\n\ninterface CardProps {\n  title: string;\n  children: ReactNode;\n}\n\nfunction Card({ title, children }: CardProps) {\n  return (\n    <div className="card">\n      <h2>{title}</h2>\n      <div className="card-content">\n        {children}\n      </div>\n    </div>\n  );\n}\n\n// الاستخدام:\n<Card title="بطاقتي">\n  <p>هذا النص سيتم عرضه</p>\n  {123} {/* الأرقام تعمل أيضًا */}\n  {null} {/* و null أيضًا */}\n</Card>
\n\n

ما الذي يتضمنه ReactNode؟ في الواقع هو اتحاد (Union) من:

\n
    \n
  • ReactElement — عناصر JSX
  • \n
  • string و number — الأنواع البدائية
  • \n
  • boolean و null و undefined — يتم تجاهلها أثناء العرض
  • \n
  • ReactNode[] — مصفوفة مما سبق
  • \n
  • ReactPortal — البوابات (Portals)
  • \n
\n\n

2. ReactElement — الوضع الصارم

\n\n

إذا كنت بحاجة إلى أن يكون children عنصر JSX فقط (وليس نصًا أو رقمًا)، استخدم ReactElement.

\n\n
import { ReactElement } from 'react';\n\ninterface StrictCardProps {\n  children: ReactElement; // عنصر JSX واحد فقط\n}\n\nfunction StrictCard({ children }: StrictCardProps) {\n  return <div className="strict-card">{children}</div>;\n}\n\n// يعمل:\n<StrictCard><span>عنصر فقط</span></StrictCard>\n\n// خطأ من TypeScript:\n<StrictCard>نص</StrictCard> // ❌ النص غير مناسب
\n\n

مهم: ReactElement يتطلب عنصرًا فرعيًا واحدًا بالضبط. إذا قمت بتمرير عنصرين بدون غلاف، فسيظهر خطأ من TypeScript أيضًا.

\n\n

3. JSX.Element — اسم مستعار لـ ReactElement

\n\n

النوع JSX.Element هو ببساطة ReactElement<any, any>. إنه أقل مرونة من ReactNode، ولا يُنصح به عمومًا لـ children إلا إذا كنت تكتب مكتبة.

\n\n
// في الأساس، هما نفس الشيء:\ntype A = JSX.Element;    // ReactElement<any, any>\ntype B = ReactElement;   // Re                

المدونات

توصيات الكتب