Menu
flag Ar iconالعربيةdown icon

أنواع Union في TypeScript: العامل | مع أمثلة

نوع union مثل string | number يعني أن القيمة يمكن أن تكون أيًا من عدة أنواع. تعرّف على ما يمكنك فعله بـ union (فقط ما يدعمه كل عضو)، وطريقة تضييقه، وunion من القيم الحرفية وأنواع الكائنات، والفرق بين (A | B)[] وA[] | B[].

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

يسرد نوع union البدائل بـ |: قيمة من نوع string | number إما نص أو رقم. الـ unions هي طريقة TypeScript في وصف القيم التي يمكن أن تأخذ أكثر من شكل بشكل مشروع، ويجبرك المترجم على فحص الشكل الذي لديك قبل استخدام أي شيء خاص به.

داخل كل فرع من فحص typeof يكون لـ id نوع واحد. تُسمى هذه الخطوة التضييق (narrowing)، وهي ما يجعل الـ unions عملية.

الأعضاء المشتركة فقط مسموحة

قبل التضييق لا تستطيع استخدام إلا ما يدعمه كل عضو في الـ union. toString() موجودة في النصوص والأرقام، فلا مشكلة فيها؛ أما toUpperCase() فموجودة في النصوص فقط:

index.ts(3,16): error TS2339: Property 'toUpperCase' does not exist on type 'string | number'.
  Property 'toUpperCase' does not exist on type 'number'.

يسمّي السطر الثاني العضو الذي تنقصه الخاصية. وتنطبق القاعدة نفسها في الاتجاه الآخر: لا يمكن تمرير قيمة string | number إلى معامل نوعه string (TS2345)، لأنها قد تكون رقمًا. يقبل الـ union قيمًا أكثر، وفي المقابل يتيح لك فعل أقل بها حتى تفحص.

تضييق union

يستخدم التضييق فحوص JavaScript العادية. تتبع TypeScript مسار التحكم وتحذف الأعضاء كلما استُبعدت، فبعد آخر فحص لا يبقى إلا عضو واحد:

الفحصيضيّق إلىمناسب لـ
typeof x === "string"النوع البدائيstring وnumber وboolean وbigint وsymbol وundefined وfunction
x === null وx === "a"القيمة المقارَنةnull وundefined والأعضاء الحرفية
Array.isArray(x)عضو المصفوفةالمصفوفات
x instanceof Dateالصنفنسخ الأصناف
"meow" in xالأعضاء التي تملك الخاصيةأنواع الكائنات
x.kind === "circle"العضو الذي يحمل ذلك الوسمdiscriminated unions
isCat(x) (تعيد x is Cat)ما تقوله الدالةأي شيء، منطق مخصص

القائمة الكاملة لصيغ التضييق موجودة في صفحة تضييق الأنواع.

Union من الأنواع الحرفية

الـ union من القيم الحرفية مجموعة مغلقة من القيم المسموحة. وهو أكثر أنواع union شيوعًا في الكود الحقيقي:

type Status = "idle" | "loading" | "success" | "error";
type Dice = 1 | 2 | 3 | 4 | 5 | 6;
type Toggle = "on" | "off" | boolean; // boolean is itself true | false

let current: Status = "idle";
current = "loading";   // fine
current = "finished";  // error TS2322: Type '"finished"' is not assignable to type 'Status'.

المقارنة مع قيمة حرفية تضيّق: بعد if (current === "error") يعرف فرع else أن current واحدة من القيم الثلاث الأخرى. تحل الـ unions الحرفية محل enums في قواعد كود كثيرة؛ انظر الأنواع الحرفية لـ as const وطريقة اشتقاق union كهذا من مصفوفة.

Union من أنواع الكائنات

عندما تكون الأعضاء أنواع كائنات، تتاح الخصائص التي تشترك فيها كلها مباشرة. أما الباقي فافحص وجود الخاصية بـ in:

لـ unions من عدة أشكال كائنات، النمط الأنظف هو خاصية حرفية مشتركة مثل kind: "cat" / kind: "fish". فحص تلك الخاصية الواحدة يضيّق الكائن كله، ويمكن التحقق من شمولية switch عليها. هذا النمط هو discriminated union.

المصفوفات وأنواع union

مكان الأقواس يغيّر المعنى كليًا:

النوعالمعنىقيمة مثال
(string | number)[]مصفوفة كل عنصر فيها نص أو رقم[1, "two", 3]
string[] | number[]مصفوفة نصوص فقط، أو مصفوفة أرقام فقط["a", "b"]
string | number[]نص، أو مصفوفة أرقام (| أضعف ارتباطًا من [])"text"

عند التكرار على (string | number)[] يكون كل عنصر هو الـ union ويحتاج إلى تضييق، كما في دالة reduce أعلاه. وتعمل دوال مثل map وfilter أيضًا على string[] | number[]، وتستقبل الدالة الممررة string | number.

Union مع null و undefined

أكثر أنواع union شيوعًا على الإطلاق هو «قيمة أو لا شيء»: string | null وUser | undefined. وهو ما تعيده Array.prototype.find وMap.prototype.get، والخاصية الاختيارية name?: string تُقرأ كـ string | undefined. ولمعالجتها بـ ?. و?? وفحوص null صفحة خاصة: null و undefined.

لحذف أعضاء من union موجود على مستوى الأنواع، استخدم الأدوات المدمجة: Exclude<"a" | "b" | "c", "a"> هو "b" | "c"، وNonNullable<string | null> هو string.

الأسئلة الشائعة

ما هو نوع union في TypeScript؟

نوع مكوّن من عدة بدائل مربوطة بـ |. قيمة من نوع string | number يمكن أن تكون نصًا أو رقمًا. لا يسمح لك المترجم إلا باستخدام ما تشترك فيه كل الأعضاء حتى تضيّق القيمة إلى عضو واحد بفحص مثل typeof value === "string".

لماذا تقول TypeScript إن خاصية غير موجودة في نوع union؟

لأن عضوًا واحدًا على الأقل من الـ union لا يملكها. الخطأ TS2339، مثل Property 'toUpperCase' does not exist on type 'string | number'، يعني أن القيمة قد تكون رقمًا، والرقم لا يملك toUpperCase. ضيّق أولًا (typeof أو in أو Array.isArray أو instanceof أو فحص المميّز)، ثم استخدم الخاصية الخاصة بالعضو.

كيف أعرّف مصفوفة تحمل أكثر من نوع؟

ضع الـ union بين قوسين: (string | number)[] أو Array<string | number>، حيث يمكن أن يكون كل عنصر من أي من النوعين. أما string[] | number[] فمختلف: المصفوفة كلها نصوص أو كلها أرقام. ودون أقواس تعني string | number[] نصًا أو مصفوفة أرقام.

ما الفرق بين نوع union ونوع intersection؟

الـ union A | B قيمة هي أحد النوعين، فلا تستطيع استخدام إلا ما يشتركان فيه. والـ intersection A & B قيمة هي النوعان معًا، فتملك كل أعضاء الاثنين. وفي أنواع الكائنات، يقبل A | B قيمًا أكثر ويتطلب A & B خصائص أكثر.

كيف أعرف أي نوع هي قيمة union؟

استخدم فحصًا وقت التشغيل تفهمه TypeScript: typeof x === "string" للأنواع البدائية، وArray.isArray(x) للمصفوفات، وx instanceof Date للأصناف، و"prop" in x لأشكال الكائنات، أو x.kind === "circle" عندما تشترك الأعضاء في وسم حرفي. وللمنطق المخصص، اكتب دالة type guard تعيد x is T.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن