مصفوفات الكائنات في TypeScript: دليل تعليمي خطوة بخطوة لمن سئم من الأخطاء
\n\nهل سبق لك أن كتبت كودًا بلغة TypeScript وفجأة ظهر لك خط أحمر من IDE عندما حاولت إضافة كائن إلى مصفوفة؟ مألوف، أليس كذلك؟ سؤال "How can I define an array of objects?" هو أحد أكثر الأسئلة شيوعًا على Stack Overflow. وليس من دون سبب: بدون كتابة الأنواع الصحيحة لمصفوفات الكائنات، يتحول كودك إلى مصدر للأخطاء والصداع.
\n\nفي هذا الدليل التعليمي، سنستعرض جميع طرق تعريف مصفوفة الكائنات في TypeScript - من البسيطة إلى المتقدمة. ستتعلم كيفية تجنب الأخطاء الشائعة، وكيفية استخدام الواجهات، وكيفية جعل كودك ليس فقط عمليًا بل أيضًا جميلًا. هيا بنا!
\n\nلماذا لا يعمل [] البسيط؟
\n\nلنفترض أنك تكتب:
\n\nlet users = [];\n\nيرى TypeScript هذا على أنه never[] - مصفوفة لا يجب أن تحتوي على عناصر أبدًا. حاول إضافة كائن إليها:
users.push({ name: 'آنا', age: 25 }); // خطأ!\n\nسيصرخ IDE: "Argument of type '{ name: string; age: number; }' is not assignable to parameter of type 'never'." لا يعرف TypeScript ما الذي تنوي تخزينه في المصفوفة، لذلك يمنع أي إضافات.
\n\nالحل هو تحديد نوع المصفوفة بوضوح. دعنا نستعرض جميع الخيارات.
\n\nالطريقة 1: تعليق النوع الأساسي - الأقواس المربعة
\n\nأبسط وأكثر طريقة بديهية هي استخدام الصياغة Type[]:
let users: { name: string; age: number }[] = [];\n\nusers.push({ name: 'آنا', age: 25 }); // ✅ يعمل\nusers.push({ name: 'إيفان', age: 30 }); // ✅ يعمل\n\n\nهنا نقول لـ TypeScript: "يا هذا، هذه مصفوفة كائنات، كل منها يحتوي على خصائص name (سلسلة نصية) و age (رقم)". IDE الآن راضٍ، الإكمال التلقائي يعمل، ويتم اكتشاف أخطاء الأنواع في مرحلة التجميع.
\n\nالعيب: إذا كان هيكل الكائن معقدًا، يصبح الوصف مباشرة في التعليق ضخمًا. لمثل هذه الحالات، تم اختراع الواجهات.
\n\nالطريقة 2: الواجهات - أفضل صديق لك
\n\nتسمح لك الواجهات بإخراج وصف الكائن إلى كيان منفصل وإعادة استخدامه. هذا يجعل الكود أنظف وأوضح:
\n\ninterface User {\n id: number;\n name: string;\n age: number;\n email?: string; // خاصية اختيارية\n}\n\nlet users: User[] = [];\n\nusers.push({ id: 1, name: 'آنا', age: 25 });\nusers.push({ id: 2, name: 'إيفان', age: 30, email: 'ivan@example.com' }); // ✅\n\n\nالآن إذا حاولت إضافة كائن بدون حقل id أو بنوع خاطئ، سيعطيك TypeScript خطأ. الواجهات مفيدة بشكل خاص عندما يتم استخدام نفس نوع الكائن في عدة أماكن.
وماذا عن type؟
\n\nبدلاً من interface يمكنك استخدام type:
type User = {\n id: number;\n name: string;\n age: number;\n};\n\nlet users: User[] = [];\n\nالفرق بين interface و type هو موضوع لمقال منفصل. بالنسبة لمصفوفات الكائنات، يمكن استخدام كلا الخيارين، لكن interface يُستخدم غالبًا لوصف أشكال الكائنات.
الطريقة 3: صياغة Generic Array<Type>
\n\nطريقة بديلة هي استخدام الأدوية (Generics):
\n\nlet users: Array<{ name: string; age: number }> = [];\n\n// أو مع واجهة:\nlet users: Array<User> = [];\n\n\nكلا الصياغتين (Type[] و Array<Type>) تعملان بنفس الطريقة. الاختيار مسألة ذوق وسياق. شخصيًا، أفضل Type[] للأنواع البسيطة و Array<Type> للتركيبات المعقدة للأدوية. لكن الأهم هو أن تكون متسقًا في المشروع.
الطريقة 4: إنشاء مصفوفة بكائنات أولية
\n\nغالبًا ما تحتاج المصفوفة ليس فقط إلى التصريح عنها، بل أيضًا إلى ملئها بالبيانات فورًا. TypeScr