TypeScript: أنواع الاتحاد وأنواع القيم الثابتة في TypeScript

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

تُعد أنواع الاتحاد وأنواع القيم الثابتة الخطوة الأولى في التقدم الذي حققته لغة TypeScript مقارنةً بلغة JavaScript — فهي تتيح لك التعبير عن أن «هذه القيمة يمكن أن تكون إما A أو B» وأن «هذه القيمة لا يمكن أن تكون إلا أحد هذه الخيارات».

1. أنواع الاتحادات

يستخدم نوع الاتحاد | لدمج أنواع متعددة، مما يشير إلى أن «القيمة يمكن أن تكون أي نوع من هذه الأنواع»:

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

TYPESCRIPT
let id: number | string;

id = 42;        // ✅ number Legal
id = "ABC";     // ✅ string Legal
id = true;      // ❌ boolean Not in a composite type

(2) الاستخدامات الشائعة: معلمات الدالة

يتمثل الاستخدام الأكثر شيوعًا لأنواع الاتحاد في السماح للدوال بقبول معلمات من أنواع مختلفة:

TYPESCRIPT
function printId(id: number | string) {
  console.log("YourID: :" + id);
}

printId(42);       // ✅
printId("ABC");    // ✅
printId(true);     // ❌

(3) القيود المفروضة على أنواع الاتحادات

لا يمكن للمتغيرات من نوع الاتحاد الوصول إلا إلى العناصر المشتركة بين جميع الأنواع:

TYPESCRIPT
function process(value: number | string) {
  // value.toString()   // ✅ number and string All of them toString
  // value.toUpperCase() // ❌ number None toUpperCase
  // value.toFixed(2)    // ❌ string None toFixed
}
📌 السبب: يجب أن يضمن TypeScript بقاء الكود آمنًا حتى عندما يكون value أي عنصر من عناصر الاتحاد. لا يمكن استدعاء سوى الخصائص والطرق المشتركة بين جميع العناصر بشكل مباشر. للوصول إلى عنصر من نوع معين، يجب أولاً استخدام «تضييق النوع» (انظر القسم 3).



2. أنواع القيم الحرفية

تقصر الأنواع الحرفية قيمة المتغير على قيم حرفية محددة — ليس «أي سلسلة»، بل «هذه السلاسل المحددة فقط».

(1) ثلاثة أنواع من القيم الثابتة

الأنواع الحرفية قواعد الصياغة مثال
سلسلة نصية "value1" | "value2" "north" | "south" | "east" | "west"
القيم العددية 1 | 2 | 3 0 | 1 | 2
قيمة منطقية ثابتة true | false تساوي فعليًّا boolean (قيمتان فقط)

(2) أنواع القيم النصية الثابتة

TYPESCRIPT
let direction: "north" | "south" | "east" | "west";

direction = "north";    // ✅
direction = "up";       // ❌ "up" Not in a composite type

(3) أنواع القيم العددية الثابتة

TYPESCRIPT
type HttpStatusCode = 200 | 301 | 404 | 500;

let code: HttpStatusCode = 200;   // ✅
let code2: HttpStatusCode = 201;  // ❌ 201 Not in a composite type

(4) أنواع القيم الثابتة المنطقية

TYPESCRIPT
type YesNo = true | false;  // equivalent to boolean
type StrictTrue = true;     // It can only be true
💡 نصيحة: لا يحمل النوع الثابت المنطقي (منطقي) معنىً كبيرًا بحد ذاته (true | false هو مجرد قيمة منطقية)، لكنه يكون مفيدًا عند دمجه مع أنواع أخرى في الأنواع المجمعة: string | true يمثل «سلسلة أو القيمة "true"».

▶ مثال: تحديد أذونات الأدوار باستخدام الأنواع الحرفية

TYPESCRIPT
type Role = "admin" | "editor" | "viewer";

function checkPermission(role: Role) {
  if (role === "admin") {
    console.log("Administrator:Full Access");
  } else if (role === "editor") {
    console.log("Editor:Editable Content");
  } else {
    console.log("Viewers:Read-only access");
  }
}

checkPermission("admin");   // ✅
checkPermission("editor");  // ✅
checkPermission("guest");   // ❌ Compilation Error——"guest" Not legal Role
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
Administrator:Full Access
Editor:Editable Content


3. تضييق النوع (Type Narrowing)

لا يمكن للمتغيرات من نوع الاتحاد الوصول مباشرةً إلى عناصر من نوع معين، ولكن يمكن تضييق نطاقها من خلال «تضييق النوع».

(1) تضييق نطاق typeof

TYPESCRIPT
function process(value: number | string) {
  if (typeof value === "string") {
    // In this branch,TypeScript knows value is string
    console.log(value.toUpperCase());  // ✅ string Methods
  } else {
    // In this branch,TypeScript knows value is number
    console.log(value.toFixed(2));     // ✅ number Methods
  }
}

(2) تضييق نطاق المساواة

TYPESCRIPT
function compare(a: string | number, b: string | boolean) {
  if (a === b) {
    // a and b equal,Their intersection type is string
    console.log(a.toUpperCase());  // ✅ Here a It must be string
  }
}

(3) تضييق نطاق عامل in

TYPESCRIPT
function process(input: { name: string } | { age: number }) {
  if ("name" in input) {
    console.log(input.name);  // ✅ Has name property,Inferred as { name: string }
  } else {
    console.log(input.age);   // ✅ None name,Inferred as { age: number }
  }
}

(4) تضييق نطاق instanceof

TYPESCRIPT
function processDate(value: Date | string) {
  if (value instanceof Date) {
    console.log(value.toISOString());  // ✅ Date Methods
  } else {
    console.log(value.toUpperCase());  // ✅ string Methods
  }
}

▶ مثال: شرح شامل لتضييق النوع

TYPESCRIPT
function formatValue(value: number | string | boolean): string {
  if (typeof value === "number") {
    return "Numbers:" + value.toFixed(2);
  } else if (typeof value === "string") {
    return "String:" + value.toUpperCase();
  } else {
    return "Boolean:" + value;
  }
}

console.log(formatValue(3.14159));
console.log(formatValue("hello"));
console.log(formatValue(true));
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
Numbers:3.14
String:HELLO
Boolean:true


4. الأنماط الكلاسيكية لأنواع الاتحاد وأنواع القيم الثابتة

يمكن أن يؤدي الجمع بين أنواع الاتحاد وأنواع القيم الثابتة إلى تقييدات أنواع قوية جدًّا. وفيما يلي ثلاثة أنماط كلاسيكية:

(1) النمط 1: الاتحاد التمييزي

يمكن التمييز بين أعضاء الاتحاد باستخدام قيم حرفية مختلفة لنفس الخاصية:

TYPESCRIPT
interface Circle {
  kind: "circle";       // Identifiable Attributes
  radius: number;
}

interface Rectangle {
  kind: "rectangle";    // Identifiable Attributes
  width: number;
  height: number;
}

type Shape = Circle | Rectangle;

function getArea(shape: Shape): number {
  if (shape.kind === "circle") {
    return Math.PI * shape.radius ** 2;   // ✅ Accessible radius
  } else {
    return shape.width * shape.height;     // ✅ Accessible width、height
  }
}
📌 نقطة أساسية: تحتوي كل واجهة على خاصية kind، لكن قيمتها تكون من نوع ثابت مختلف. يستخدم TypeScript قيمة kind لتضييق النوع والوصول بأمان إلى الخصائص الخاصة بتلك الواجهة.

(2) النمط 2: القيم الاختيارية + غير محددة

TYPESCRIPT
type Result = string | undefined;

function search(query: string): Result {
  if (query.length === 0) return undefined;
  return "Found:" + query;
}

let result = search("TypeScript");
if (result !== undefined) {
  console.log(result.toUpperCase());  // ✅ narrowed to string
}

(3) النمط 3: آلة الحالات

TYPESCRIPT
type RequestStatus = "idle" | "loading" | "success" | "error";

interface RequestState {
  status: RequestStatus;
  data?: string;
  error?: string;
}

function renderState(state: RequestState): string {
  switch (state.status) {
    case "idle":
      return "Waiting......";
    case "loading":
      return "Loading......";
    case "success":
      return "Success:" + state.data;    // ✅ success in that state data Existence
    case "error":
      return "Error:" + state.error;   // ✅ error in that state error Existence
  }
}


5. النوع never والعمليات الشاملة للتحقق

عندما يقتصر TypeScript على «سيناريو مستحيل»، يصبح النوع never:

TYPESCRIPT
type Shape = "circle" | "square";

function getIcon(shape: Shape): string {
  switch (shape) {
    case "circle": return "⭕";
    case "square": return "⬜";
    default:
      // If all case It's all taken care of.,shape Here, the type is never
      const _exhaustiveCheck: never = shape;  // ✅ If omitted case,An error will occur here
      return _exhaustiveCheck;
  }
}
💡 نصيحة: نمط الفحص الشامل لـ never — تعيين قيمة لمتغير من نوع never في الفرع default من عبارة switch. إذا أضفت عضوًا جديدًا إلى Shape في المستقبل ولكنك نسيت إضافة case المقابل، فسيُصدر TypeScript خطأً في الفرع default، ويطالبك بإضافته.

▶ مثال: الأثر العملي للتدقيق الشامل

TYPESCRIPT
type TrafficLight = "red" | "yellow" | "green";

function getAction(light: TrafficLight): string {
  switch (light) {
    case "red": return "Stop";
    case "yellow": return "Note";
    // Intentional omission "green" 's case
    default:
      // If you add the next line,TypeScript It will throw an error:
      // You cannot convert the type "green" Assignment to a Type "never"
      const exhaustive: never = light;
      return "Unknown";
  }
}
▶ جرّب الكود

الناتج:

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


❓ أسئلة شائعة

س ما الفرق بين أنواع الاتحاد وأنواع التقاطع؟
ج نوع الاتحاد (A | B) يعني «إما A أو B» — فهو يأخذ الاتحاد، لذا يكفي أن تستوفي القيمة أحد هذين النوعين فقط. أما نوع التقاطع (A & B) فيعني «A و B معًا» — فهو يأخذ التقاطع، لذا يجب أن تستوفي القيمة كلا النوعين. سيشرح الدرس 20 أنواع التقاطع بالتفصيل.
س أيهما يجب أن أستخدم: الأنواع الحرفية أم القوائم؟
ج يُفضل استخدام الأنواع الحرفية المجمعة. فهي أخف وزنًا من القوائم (لا يتم إنشاء أي كود إضافي في وقت التحويل البرمجي) ومتوافقة تمامًا مع السلاسل والأرقام الأصلية في JavaScript. أما القوائم فهي مناسبة للحالات التي تتطلب التعيين العكسي (القيمة → الاسم) أو التي تحتاج فيها إلى التكرار على جميع العناصر في وقت التشغيل. سيقوم الدرس 12 بمقارنة النوعين.
س هل يمكن لـ typeof اكتشاف جميع الأنواع؟
ج لا. لا يمكن لـ typeof تحديد سوى الأنواع التالية: "number" و"سلسلة" و"منطقي" و"symbol" و"bigint" و"كائن" و"دالة" و"غير معرّف". بالنسبة لأنواع المراجع مثل null (typeof null تُرجع "كائن")، والمصفوفات، وDate، تحتاج إلى استخدام instanceof أو طرق أخرى لتحديد النوع. انظر الدرس 17 للحصول على شرح مفصل.
س متى يُستخدم النوع never؟
ج يظهر النوع never بشكل أساسي في حالتين: (1) يظهر تلقائيًا عندما يتم تضييق نطاق النوع إلى فرع مستحيل، و(2) عندما لا تُرجع الدالة أي قيمة أبدًا (مثل عند إلقاء استثناء أو حدوث حلقة لا نهائية). يكتفي المبتدئون بفهم نمط «الفحص الشامل» — باستخدام never في جملة default التابعة لـ switch للتحقق من وجود أي case مفقودة.

📖 ملخص

📝 تمارين

  1. المسألة الأساسية (مستوى الصعوبة ⭐): عرّف نوع الاتحاد Status = "active" | "inactive" | "banned" واكتب دالة getStatusText(status: Status) تُرجع الوصف الصيني المقابل.
  2. مشكلة متقدمة (درجة الصعوبة ⭐⭐): عرَّف نوع اتحاد قابل للتمييز Result = SuccessResult | ErrorResult، حيث يتكون SuccessResult من success: true وdata: string، ويتكون ErrorResult من success: false وerror: string. اكتب دالة تعالج Result، بناءً على قيمة success, safely accesses either data or خطأ.
  3. مشكلة التحدي (الصعوبة ⭐⭐⭐): اكتب دالة describeDay(day: "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | "sun") باستخدام الفحص الشامل لمعالجة جميع الأيام السبعة في عبارة switch. بعد ذلك، احذف يومًا واحدًا عن قصد ولاحظ رسالة الخطأ التي تنتج عن الفحص الشامل الذي «لا يُجرى أبدًا».
Web-Tutorial.com

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

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

100%