Array<Type> مقابل Type[] في TypeScript: معركة الصياغة التي يجب أن تربحها
\n\nإذا كنت قد كتبت أي كود بلغة TypeScript من قبل، فبالتأكيد رأيت طريقتين للإعلان عن مصفوفة أرقام:
\n\nconst numbers1: number[] = [1, 2, 3];\nconst numbers2: Array<number> = [1, 2, 3];\n\nكلا الخيارين يعملان. كلاهما يتم تجميعهما. كلاهما TypeScript صحيح. فلماذا كل هذا الجدل حولهما؟ لماذا جمع هذا السؤال على Stack Overflow آلاف المشاهدات؟ والأهم من ذلك - كيف لا تقع في الأخطاء التي قد تدمر مشروعك؟
\n\nدعنا نفهم الأمر مرة واحدة وإلى الأبد. بدون نظرية مملة. فقط ما سيفيدك حقًا في الميدان.
\n\nشرح موجز: ما هو ما
\n\nصياغة Type[] (صياغة المصفوفة الحرفية)
\n\nهذه هي الطريقة الأكثر شيوعًا للإعلان عن مصفوفة في TypeScript. لقد جاءت من JavaScript وتبدو طبيعية:
\n\nlet fruits: string[] = ['apple', 'banana', 'cherry'];\nlet matrix: number[][] = [[1, 2], [3, 4]]; // مصفوفة من المصفوفات\n\nقصيرة، قابلة للقراءة، بديهية. في 90% من الحالات، هذا يكفي.
\n\nصياغة Array<Type> (صياغة الأدوية العامة)
\n\nهذه هي صيغة الأدوية العامة (Generic) التي تستخدم الواجهة المدمجة Array<T>:
let fruits: Array<string> = ['apple', 'banana', 'cherry'];\nlet matrix: Array<Array<number>> = [[1, 2], [3, 4]];\n\nتبدو أكثر "أكاديمية"، لكنها توفر مرونة أكبر في السيناريوهات المعقدة.
\n\nأفضل 5 أخطاء يرتكبها حتى المطورون ذوو الخبرة
\n\nالخطأ رقم 1: الثقة العمياء في الإكمال التلقائي لبيئة التطوير
\n\nقد تقترح بيئة التطوير الخاصة بك كلا الخيارين. لكن هذا لا يعني أنهما قابلان للتبادل في كل مكان. لننظر إلى مثال مع أنواع الاتحاد (union types):
\n\n// هذا ممكن\ntype Status = 'active' | 'inactive';\nconst statuses1: Status[] = ['active', 'inactive'];\n\n// أما هكذا - خطأ نحوي!\n// const statuses2: Array<'active' | 'inactive'> = ['active', 'inactive']; \n// ❌ خطأ: ';' متوقع\n\n// الخيار الصحيح مع الأدوية العامة:\nconst statuses3: Array<Status> = ['active', 'inactive'];\n\nالخلاصة: داخل Array<> لا يمكن استخدام أنواع الاتحاد المعقدة مباشرة. قم أولاً باستخراجها في نوع منفصل.
الخطأ رقم 2: الخلط مع المصفوفات غير القابلة للتعديل (readonly)
\n\nعندما تحتاج إلى جعل المصفوفة غير قابلة للتغيير، تتصرف الصياغتان بشكل مختلف:
\n\n// ✅ صحيح مع Type[]\nconst readonlyFruits: readonly string[] = ['apple', 'banana'];\n// readonlyFruits.push('orange'); // ❌ خطأ: readonly\n\n// ❌ هكذا لن يعمل:\n// const wrong: readonly Array<string> = ['apple']; \n// خطأ: معدّل 'readonly' يمكن أن يظهر فقط على أنواع المصفوفات\n\n// ✅ صحيح مع Array<> - استخدم ReadonlyArray:\nconst correct: ReadonlyArray<string> = ['apple', 'banana'];\n\nالخلاصة: للمصفوفات غير القابلة للتعديل، استخدم readonly Type[] أو ReadonlyArray<Type>. لا يمكن خلط readonly مع Array<>.
الخطأ رقم 3: مشاكل مع المصفوفات متعددة المستويات
\n\nعندما تحتوي المصفوفة على مصفوفات أخرى، تصبح صياغة Array<> ضخمة:
// مقروءة وواضحة\nconst grid1: number[][] = [[1, 2], [3, 4]];\n\n// بالفعل أصعب في القراءة\nconst grid2: Array<Array<number>> = [[1, 2], [3, 4]];\n\n// وماذا لو كان هناك ثلاثة مستويات؟ كابوس:\nconst cube: Array<Array<Array<number>>> = [[[1]]]; // 🤯\n\n// مع Type[] الأمر أبسط:\nconst cube2: number[][][] = [[[1]]];\n\nالخلاصة: للمصفوفات ذات التداخل أكثر من مستويين، استخدم Type[][]. زملاؤك سيشكرونك.
الخطأ رقم 4: تجاهل سياق الاستخدام
\n\nفي بعض الأطر (Angular, React) والمكتبات، هناك نمط معين متبع. مخالفة الاتفاقية قد تسبب ارتباكًا:
\n\n// Angular غالبًا ما يستخدم