TypeScript: أنواع الاتحاد وأنواع القيم الثابتة في TypeScript
آخر تحديث: 2026-08-26
تُعد أنواع الاتحاد وأنواع القيم الثابتة الخطوة الأولى في التقدم الذي حققته لغة TypeScript مقارنةً بلغة JavaScript — فهي تتيح لك التعبير عن أن «هذه القيمة يمكن أن تكون إما A أو B» وأن «هذه القيمة لا يمكن أن تكون إلا أحد هذه الخيارات».
1. أنواع الاتحادات
يستخدم نوع الاتحاد | لدمج أنواع متعددة، مما يشير إلى أن «القيمة يمكن أن تكون أي نوع من هذه الأنواع»:
(1) قواعد النحو الأساسية
let id: number | string;
id = 42; // ✅ number Legal
id = "ABC"; // ✅ string Legal
id = true; // ❌ boolean Not in a composite type
(2) الاستخدامات الشائعة: معلمات الدالة
يتمثل الاستخدام الأكثر شيوعًا لأنواع الاتحاد في السماح للدوال بقبول معلمات من أنواع مختلفة:
function printId(id: number | string) {
console.log("YourID: :" + id);
}
printId(42); // ✅
printId("ABC"); // ✅
printId(true); // ❌
(3) القيود المفروضة على أنواع الاتحادات
لا يمكن للمتغيرات من نوع الاتحاد الوصول إلا إلى العناصر المشتركة بين جميع الأنواع:
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
}
value أي عنصر من عناصر الاتحاد. لا يمكن استدعاء سوى الخصائص والطرق المشتركة بين جميع العناصر بشكل مباشر. للوصول إلى عنصر من نوع معين، يجب أولاً استخدام «تضييق النوع» (انظر القسم 3).
2. أنواع القيم الحرفية
تقصر الأنواع الحرفية قيمة المتغير على قيم حرفية محددة — ليس «أي سلسلة»، بل «هذه السلاسل المحددة فقط».
(1) ثلاثة أنواع من القيم الثابتة
| الأنواع الحرفية | قواعد الصياغة | مثال |
|---|---|---|
| سلسلة نصية | "value1" | "value2" |
"north" | "south" | "east" | "west" |
| القيم العددية | 1 | 2 | 3 |
0 | 1 | 2 |
| قيمة منطقية ثابتة | true | false |
تساوي فعليًّا boolean (قيمتان فقط) |
(2) أنواع القيم النصية الثابتة
let direction: "north" | "south" | "east" | "west";
direction = "north"; // ✅
direction = "up"; // ❌ "up" Not in a composite type
(3) أنواع القيم العددية الثابتة
type HttpStatusCode = 200 | 301 | 404 | 500;
let code: HttpStatusCode = 200; // ✅
let code2: HttpStatusCode = 201; // ❌ 201 Not in a composite type
(4) أنواع القيم الثابتة المنطقية
type YesNo = true | false; // equivalent to boolean
type StrictTrue = true; // It can only be true
true | false هو مجرد قيمة منطقية)، لكنه يكون مفيدًا عند دمجه مع أنواع أخرى في الأنواع المجمعة: string | true يمثل «سلسلة أو القيمة "true"».
▶ مثال: تحديد أذونات الأدوار باستخدام الأنواع الحرفية
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
الناتج:
Administrator:Full Access
Editor:Editable Content
3. تضييق النوع (Type Narrowing)
لا يمكن للمتغيرات من نوع الاتحاد الوصول مباشرةً إلى عناصر من نوع معين، ولكن يمكن تضييق نطاقها من خلال «تضييق النوع».
(1) تضييق نطاق typeof
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) تضييق نطاق المساواة
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
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
function processDate(value: Date | string) {
if (value instanceof Date) {
console.log(value.toISOString()); // ✅ Date Methods
} else {
console.log(value.toUpperCase()); // ✅ string Methods
}
}
▶ مثال: شرح شامل لتضييق النوع
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));
الناتج:
Numbers:3.14
String:HELLO
Boolean:true
4. الأنماط الكلاسيكية لأنواع الاتحاد وأنواع القيم الثابتة
يمكن أن يؤدي الجمع بين أنواع الاتحاد وأنواع القيم الثابتة إلى تقييدات أنواع قوية جدًّا. وفيما يلي ثلاثة أنماط كلاسيكية:
(1) النمط 1: الاتحاد التمييزي
يمكن التمييز بين أعضاء الاتحاد باستخدام قيم حرفية مختلفة لنفس الخاصية:
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: القيم الاختيارية + غير محددة
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: آلة الحالات
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:
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، ويطالبك بإضافته.
▶ مثال: الأثر العملي للتدقيق الشامل
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";
}
}
الناتج:
// Executed successfully
❓ أسئلة شائعة
typeof اكتشاف جميع الأنواع؟typeof تحديد سوى الأنواع التالية: "number" و"سلسلة" و"منطقي" و"symbol" و"bigint" و"كائن" و"دالة" و"غير معرّف". بالنسبة لأنواع المراجع مثل null (typeof null تُرجع "كائن")، والمصفوفات، وDate، تحتاج إلى استخدام instanceof أو طرق أخرى لتحديد النوع. انظر الدرس 17 للحصول على شرح مفصل.never؟never بشكل أساسي في حالتين: (1) يظهر تلقائيًا عندما يتم تضييق نطاق النوع إلى فرع مستحيل، و(2) عندما لا تُرجع الدالة أي قيمة أبدًا (مثل عند إلقاء استثناء أو حدوث حلقة لا نهائية). يكتفي المبتدئون بفهم نمط «الفحص الشامل» — باستخدام never في جملة default التابعة لـ switch للتحقق من وجود أي case مفقودة.📖 ملخص
- يستخدم نوع الاتحاد
|لدمج أنواع متعددة، مما يشير إلى أن القيمة يمكن أن تكون أيًا منها - تقتصر أنواع القيم الحرفية على قيم حرفية محددة (سلاسل، أرقام، قيم منطقية)، وعندما تُدمج مع أنواع الاتحاد، فإنها تعمل كقوائم عدّية.
- لا يمكن للمتغيرات من أنواع الاتحاد الوصول إلا إلى الخصائص المشتركة بين جميع الأعضاء؛ ويجب «تضييق» نطاقها باستخدام
typeofأوinأوinstanceofللوصول إلى أعضاء محددين. - الاتحاد التمييزي هو نمط كلاسيكي يجمع بين الاتحاد والقيمة الثابتة — حيث يميز بين الأنواع بناءً على قيم السمات المشتركة.
- يُستخدم النوع
neverلإجراء فحص شامل للتأكد من أن عبارةswitchتغطي جميع الاحتمالات.
📝 تمارين
- المسألة الأساسية (مستوى الصعوبة ⭐): عرّف نوع الاتحاد
Status = "active" | "inactive" | "banned"واكتب دالةgetStatusText(status: Status)تُرجع الوصف الصيني المقابل. - مشكلة متقدمة (درجة الصعوبة ⭐⭐): عرَّف نوع اتحاد قابل للتمييز
Result = SuccessResult | ErrorResult، حيث يتكونSuccessResultمنsuccess: trueوdata: string، ويتكونErrorResultمنsuccess: falseوerror: string. اكتب دالة تعالجResult، بناءً على قيمةsuccess, safely accesses eitherdataorخطأ. - مشكلة التحدي (الصعوبة ⭐⭐⭐): اكتب دالة
describeDay(day: "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | "sun")باستخدام الفحص الشامل لمعالجة جميع الأيام السبعة في عبارة switch. بعد ذلك، احذف يومًا واحدًا عن قصد ولاحظ رسالة الخطأ التي تنتج عن الفحص الشامل الذي «لا يُجرى أبدًا».