TypeScript: قائمة TypeScript (enum)

آخر تحديث: 2026-08-26

تعد القوائم (Enums) إحدى ميزات أنواع TypeScript القليلة التي لها سلوك في وقت التشغيل — فهي تمثل نوعًا وتُنشئ كائنات JavaScript فعلية في الوقت نفسه.

1. الترقيم العددي

(1) قواعد النحو الأساسية

TYPESCRIPT
enum Direction {
  Up,       // 0(Auto-increment from 0)
  Down,     // 1
  Left,     // 2
  Right     // 3
}

let dir: Direction = Direction.Up;
console.log(dir);                // 0
console.log(Direction[0]);       // "Up"(Inverse Mapping)

(2) القيم الأولية المخصصة

TYPESCRIPT
enum Status {
  Active = 1,    // 1
  Inactive,      // 2(Auto-increment)
  Pending        // 3
}

enum HttpStatus {
  OK = 200,
  Moved = 301,
  BadRequest = 400,
  NotFound = 404,
  ServerError = 500
}

let code: HttpStatus = HttpStatus.OK;
console.log(code);  // 200

(3) التعيين العكسي للتعدادات العددية

بعد الترجمة، تُنشئ التعدادات الرقمية كائنات تعيين ثنائية الاتجاه — حيث يمكنك استرداد قيمة بناءً على اسمها، أو اسمًا بناءً على قيمته:

TYPESCRIPT
enum Role {
  Admin = 0,
  Editor = 1,
  Viewer = 2
}

// Forward Mapping: name → value
console.log(Role.Admin);   // 0

// Inverse Mapping: value → name
console.log(Role[0]);      // "Admin"
console.log(Role[1]);      // "Editor"

كود JavaScript الذي تم إنشاؤه بعد التحويل البرمجي:

JAVASCRIPT
var Role;
(function (Role) {
  Role[Role["Admin"] = 0] = "Admin";
  Role[Role["Editor"] = 1] = "Editor";
  Role[Role["Viewer"] = 2] = "Viewer";
})(Role || (Role = {}));


2. تعداد السلاسل

(1) قواعد النحو الأساسية

يجب تعيين كل عنصر من عناصر التعداد التسلسلي بشكل صريح — فلا توجد زيادة تلقائية:

TYPESCRIPT
enum EventType {
  Click = "click",
  Change = "change",
  Submit = "submit",
  Focus = "focus"
}

let event: EventType = EventType.Click;
console.log(event);  // "click"

(2) لا يوجد تعيين عكسي لتعداد السلاسل

TYPESCRIPT
enum Color {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}

console.log(Color.Red);       // "RED"  ✅ Forward Mapping
// console.log(Color["RED"]); // undefined ❌ String enumeration has no reverse mapping
💡 السبب: قيم التعدادات الرقمية هي أرقام، ويمكن استخدامها كمفاتيح للكائنات؛ أما قيم التعدادات النصية فهي سلاسل نصية، مما يتعارض مع مفاتيح الكائنات، ولذلك لا يمكن تنفيذ التعيين العكسي.

▶ مثال: تحديد حالات الطلبات باستخدام قائمة التعداد

TYPESCRIPT
enum OrderStatus {
  Pending = "PENDING",
  Processing = "PROCESSING",
  Shipped = "SHIPPED",
  Delivered = "DELIVERED",
  Cancelled = "CANCELLED"
}

function getStatusLabel(status: OrderStatus): string {
  switch (status) {
    case OrderStatus.Pending: return "Pending";
    case OrderStatus.Processing: return "Processing...";
    case OrderStatus.Shipped: return "Shipped";
    case OrderStatus.Delivered: return "Delivered";
    case OrderStatus.Cancelled: return "Canceled";
  }
}

let currentStatus: OrderStatus = OrderStatus.Processing;
console.log(`Current Status:${getStatusLabel(currentStatus)}`);
console.log(`Status Code:${currentStatus}`);
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
Current Status:Processing...
Status Code:PROCESSING


3. عمليات التعداد غير المتجانسة

يمكن أن تحتوي القوائم على مزيج من القيم الرقمية والسلسلات النصية — لكن لا يُنصح بذلك:

TYPESCRIPT
enum Mixed {
  No = 0,
  Yes = "YES"
}
⚠️ غير موصى به: قد تؤدي التعدادات غير المتجانسة بسهولة إلى حدوث لبس، كما توصي الوثائق الرسمية لـ TypeScript بتجنب استخدامها. في عملية التطوير الفعلية، يجب عليك إما استخدام التعدادات الرقمية حصريًّا أو التعدادات النصية حصريًّا.



4. التعدادات الثابتة

const enum يتم استبداله بتعبير مضمن أثناء التحويل البرمجي — ولا يُنشئ كائنًا في JavaScript، مما يوفر أداءً أفضل ولكن بوظائف محدودة:

(1) قواعد النحو الأساسية

TYPESCRIPT
const enum Color {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}

let c = Color.Red;
// After compilation:let c = "RED"(Direct Inline Replacement,No enumeration objects)

(2) قيود عمليات التعداد في const

TYPESCRIPT
const enum Direction {
  Up = "UP",
  Down = "DOWN"
}

// ❌ const Enumerations cannot use reverse mapping.
// console.log(Direction[0]);

// ❌ const Enumerations cannot be iterated over at runtime
// for (let d in Direction) { }

// ✅ Only simple value references are allowed.
let dir = Direction.Up;  // Compile to let dir = "UP"

(3) الخيار preserveConstEnums

إذا كنت تريد ألا يتم تضمين التعدادات الثابتة (const enumerations) بشكل مباشر، بل الاحتفاظ بكائنات التعداد، فقم بتمكين preserveConstEnums: true:

TYPESCRIPT
// tsconfig.json
// "preserveConstEnums": true

const enum Status {
  Active = 1
}

let s = Status.Active;
// After compilation:Enumeration objects are still generated(But quotes are also inlined.)


5. وقت التشغيل وأمان الأنواع في قوائم التعداد

(1) التعدادات كأنواع

TYPESCRIPT
enum Role {
  Admin,
  Editor,
  Viewer
}

function checkAccess(role: Role): boolean {
  return role === Role.Admin || role === Role.Editor;
}

checkAccess(Role.Admin);   // ✅
checkAccess(0);            // ✅ Numeric enumerations accept numeric values(but ⚠️ not recommended)
// checkAccess(99);        // ✅ Compilation successful!Any number can be converted to——This is a numeric enumeration vulnerability.
🔥 مخاطر التعدادات العددية: يمكن للمتغيرات من أنواع التعدادات العددية قبول أي رقم — let r: Role = 99 هي قيمة صالحة. ويرجع ذلك إلى أن التعدادات العددية صُممت مع أخذ علامات البت في الاعتبار. إذا كنت بحاجة إلى قيود صارمة على القيم، فاستخدم التعدادات السلسلية أو أنواع الاتحاد الحرفية.

(2) يعد التعداد بالسلسلة أكثر أمانًا

TYPESCRIPT
enum Role {
  Admin = "ADMIN",
  Editor = "EDITOR",
  Viewer = "VIEWER"
}

let r: Role = Role.Admin;   // ✅
// r = "ADMIN";             // ❌ String enumeration does not accept regular strings.
// r = "SUPERADMIN";        // ❌ Only enumeration members are accepted


6. قوائم التعداد مقابل أنواع الاتحاد الحرفية

الخاصية التعداد نوع الاتحاد الحرفي
كود وقت التشغيل نعم (يتم إنشاء كائنات) لا (أنواع بحتة)
التعيين العكسي التعداد الرقمي: نعم لا
تصفح جميع القيم نعم لا
قيود القيمة التعداد العددي (أكثر مرونة) صارم
تلميحات الكود الإكمال التلقائي لعناصر قائمة التعداد الإكمال التلقائي لقيم الاتحاد
حجم الحزمة يزيد من حجم الكود حجم صفر
التوافق مع JS قيم التعداد هي كائنات مخصصة سلاسل/أرقام أصلية

(1) سيناريوهات استخدام القوائم التعدادية

(2) سيناريوهات تستخدم أنواع الاتحاد الحرفي (يُنصح بها كخيار أول)

▶ مثال: مقارنة بين الطريقتين

TYPESCRIPT
// Method 1:Enumeration
enum Direction1 {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

// Method 2:Literal Union Types(Recommendations)
type Direction2 = "UP" | "DOWN" | "LEFT" | "RIGHT";

// The two are equivalent in terms of type constraints.
function move1(dir: Direction1): void { console.log(dir); }
function move2(dir: Direction2): void { console.log(dir); }

move1(Direction1.Up);  // ✅ "UP"
move2("UP");           // ✅ Use the string directly,Even simpler

// But enumerations can be iterated over
console.log(Object.values(Direction1));
// ["UP", "DOWN", "LEFT", "RIGHT"]

// Literal union types cannot be iterated over(Pure compile-time types)
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
// Executed successfully

▶ مثال: التعدادات الثابتة لأمان الأنواع بدون تكلفة

TYPESCRIPT
const enum LogLevel {
  Debug = 0,
  Info = 1,
  Warn = 2,
  Error = 3
}

function log(level: LogLevel, message: string): void {
  const prefix = ["DEBUG", "INFO", "WARN", "ERROR"][level];
  console.log(`[${prefix}] ${message}`);
}

log(LogLevel.Info, "Server started");   // Compiles to: log(1, "Server started")
log(LogLevel.Error, "Connection lost"); // Compiles to: log(3, "Connection lost")
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
[INFO] Server started
[ERROR] Connection lost
💡 نصيحة: Key Point: const enum members are inlined at compile time—no enum object is emitted in the JS output, resulting in smaller bundle size.



❓ أسئلة شائعة

س هل ينبغي استخدام التعدادات؟
ج ينقسم مجتمع TypeScript إلى معسكرين — أحدهما يرى أن التعدادات ميزة مميزة في TypeScript وينبغي استخدامها، بينما يرى الآخر أن أنواع الاتحاد الحرفية أخف وزنًا وأكثر تفضيلاً. نصيحة عملية: إذا كنت تحتاج فقط إلى قيود الأنواع (وهو ما يحدث في معظم الحالات)، فاستخدم أنواع الاتحاد الحرفية؛ أما إذا كنت بحاجة إلى سلوك وقت التشغيل (مثل التكرار أو التعيين العكسي)، فاستخدم التعدادات.
س لماذا تقبل التعدادات الرقمية أي رقم؟
ج هذا قرار تصميمي في TypeScript — تدعم التعدادات الرقمية علامات البتات (enum Perm { Read = 1, Write = 2, Execute = 4 })، وتعتبر تركيبات البتات Read | Write = 3 صالحة ولكنها غير مدرجة في تعريف التعداد. لذلك، خفف نوع التعداد الرقمي من قيوده. إذا كنت لا ترغب في هذا السلوك، فاستخدم التعدادات السلسلية أو أنواع الاتحاد الحرفية.
س ما الفرق بين قائمة التعداد const وقائمة التعداد العادية؟
ج يتم دمج قائمة التعداد const في وقت التحويل البرمجي — حيث يتم استبدال Color.Red مباشرةً بـ "RED"، ولا يتم إنشاء أي كائن لقائمة التعداد. وتتمثل الميزة في حجم حزمة أصغر وأداء أسرع في وقت التشغيل؛ أما العيب فهو أنه لا يمكن إعادة تعيينها، ولا يمكن التكرار عليها، ولا يمكن استخدامها في سياقات ديناميكية. يُفضل استخدام التعدادات const (ما لم تكن بحاجة إلى ميزات وقت التشغيل).
س هل يمكن دمج قوائم التعداد مع الواجهات أو أسماء الأنواع المستعارة؟
ج نعم. يمكن استخدام قيم قوائم التعداد كأنواع للخصائص في الواجهات—interface Config { role: Role }. كما يمكن استخدام عناصر قوائم التعداد كعناصر في أنواع الاتحاد—type Mixed = Role.Admin | "superadmin". وتُعد قوائم التعداد مفهومًا موحدًا للنوع والقيمة، مما يوفر مرونة في الاستخدام.

📖 ملخص

📝 تمارين

  1. المسألة الأساسية (الصعوبة ⭐): مع إعطاء سلسلة من القيم المُعددية Season (الربيع/الصيف/الخريف/الشتاء)، اكتب دالة تُرجع وصفًا لنطاق الأشهر المقابل بناءً على الفصل.
  2. تمرين متقدم (مستوى الصعوبة ⭐⭐): استخدم const enum لتعريف طرق HTTP (GET/POST/PUT/DELETE)، ثم قم بتعريف واجهة Request تتضمن الخصائص method وurl. أنشئ عدة كائنات طلب للتحقق من قيود الأنواع.
  3. التحدي (الصعوبة: ⭐⭐⭐): استخدم أنواع الاتحاد الحرفي بدلاً من القوائم التعدادية لتنفيذ «نظام الأذونات»: عرّف Permission = "read" | "write" | "execute" | "admin"، ثم قم بتنفيذ الدالة hasPermission(userPerms: Permission[], required: Permission): boolean للتحقق مما إذا كان المستخدم يمتلك إذنًا معينًا (يمتلك «admin» جميع الأذونات).
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%