لماذا enum وأزرار الراديو زوج مثالي؟
\nتخيل: أنت تكتب نموذجًا بلغة TypeScript. تحتاج إلى إعطاء المستخدم خيارًا واحدًا من عدة خيارات - على سبيل المثال، مستوى الصعوبة، حالة الطلب، أو الجنس. أين تخزن هذه الخيارات؟ يمكنك ترميز مصفوفة من السلاسل النصية بشكل ثابت، لكن هذا طريق مسدود. عندما تكثر الخيارات، سترتبك، وإذا تغير منطق العمل، فسيتعين عليك تعديل الكود في عشرة أماكن.
\nهنا تظهر enums (التعدادات) على المسرح. إنها تسمح لك بتعيين مجموعة من الثوابت المسماة التي يمكن للإنسان قراءتها والآلة فهمها. أما أزرار الراديو فهي عنصر واجهة مستخدم كلاسيكي لاختيار قيمة واحدة من قائمة. ربطهما يعني الحصول على كود نظيف وقابل للصيانة. يبدو رائعًا، لكن هناك فارق بسيط: كيف بالضبط تتكرر على enum لعرضه في القالب؟ هذا هو السؤال الذي يحير آلاف المطورين على Stack Overflow. دعنا نفهمه مرة واحدة وإلى الأبد.
\n\nالمشكلة: enum ليس مصفوفة
\nفي TypeScript، enum ليس مجرد قائمة من السلاسل النصية. اعتمادًا على كيفية تعريفه (رقمي أو نصي)، يتصرف بشكل مختلف. ينشئ enum الرقمي تعيينًا عكسيًا: مفتاح -> قيمة وقيمة -> مفتاح. النصي - فقط مباشر. لذلك، مجرد كتابة for (let item in MyEnum) هي فكرة سيئة. ستحصل ليس فقط على المفاتيح المطلوبة ولكن أيضًا على تعيينات عكسية غير مرغوب فيها.
إليك كيف يبدو الفخ النموذجي:
\nenum Status {\n Active = 1,\n Inactive = 2,\n Pending = 3\n}\n\n// لا تفعل هذا\nfor (let key in Status) {\n console.log(key); // "1", "2", "3", "Active", "Inactive", "Pending"\n}\n\nأرأيت؟ تم تضمين الأسماء والقيم في وحدة التحكم. إذا حاولت عرض هذا في أزرار الراديو، سيرى المستخدم أرقامًا غير مفهومة. هذا لا يناسبنا.
\n\nالحل رقم 1: Object.values() للتعدادات النصية
\nأبسط وأضمن طريقة هي استخدام Object.values(). هذه الطريقة ترجع مصفوفة من قيم الخصائص القابلة للتعداد للكائن. بالنسبة للتعدادات النصية، تعمل بشكل مثالي لأنه ليس لديها تعيين عكسي (في الغالب).
مثال: حالة الطلب
\nenum OrderStatus {\n New = 'new',\n Processing = 'processing',\n Shipped = 'shipped',\n Delivered = 'delivered',\n Cancelled = 'cancelled'\n}\n\n// الحصول على مصفوفة القيم\nconst statusValues = Object.values(OrderStatus);\n// ['new', 'processing', 'shipped', 'delivered', 'cancelled']\n\n// الآن يمكن عرضها بسهولة في القالب (React)\nfunction StatusSelector() {\n return (\n <div>\n {statusValues.map((status) => (\n <label key={status}>\n <input type="radio" name="status" value={status} />\n {status}\n </label>\n ))}\n </div>\n );\n}\n\nكل شيء عبقري بسيط. حصلنا على مصفوفة من السلاسل النصية وقمنا بتكرارها فقط. مناسب لـ React، Angular، Vue - أي إطار عمل.
\n\nالحل رقم 2: Object.keys() + التصفية للتعدادات الرقمية
\nمع التعدادات الرقمية، الوضع أكثر تعقيدًا. Object.values() سيعيد ليس فقط المفاتيح النصية ولكن أيضًا القيم الرقمية، لأن JavaScript يعتبرها "خصائص" للكائن. نحتاج إلى تصفية السلاسل النصية فقط (المفاتيح).
مثال: مستوى الوصول
\nenum AccessLevel {\n Guest = 0,\n User = 1,\n Moderator = 2,\n Admin = 3\n}\n\n// التصفية: الاحتفاظ فقط بالسلاسل النصية (المفاتيح)\nconst levelKeys = Object.keys(AccessLevel).filter(key => isNaN(Number(key)));\n// ['Guest', 'User', 'Moderator', 'Admin']\n\n// إذا كنت بحاجة إلى مصفوفة من الكائنات لعرض مناسب\nconst levelOptions = levelKeys.map(key => ({\n label: key,\n value: AccessLevel[key as keyof typeof AccessLevel]\n}));\n// [\n// { label: 'Guest', value: 0 },\n// { label: 'User', value: 1 },\n// ...\n// ]\n\nالآن لديك مصفوفة من الخيارات، حيث label هو اسم قابل للقراءة البشرية، و value هو رمز رقمي، وهو مناسب