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

Exclude وExtract وNonNullable في TypeScript: شرح وأمثلة

Exclude وExtract وNonNullable ترشّح أعضاء نوع union. تعرّف على ما يُبقيه كل منها وما يحذفه، وكيف تختار أعضاء union حسب شكلها، وكيف تُبنى من الأنواع الشرطية، وكيف تختلف عن Omit وPick.

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

يحذف Exclude<T, U> أعضاء من نوع union، ويُبقي Extract<T, U> الأعضاء المطابقة فقط، ويحذف NonNullable<T> القيمتين null وundefined. الثلاثة كلها ترشّح unions؛ ولا تمس خصائص الكائنات.

مثل كل أنواع الأدوات، هذه موجودة وقت الترجمة فقط. يرفض المترجم السطر الأخير؛ أما JavaScript الذي يعمل فلا يعرف ما هو Visible.

Exclude وExtract وNonNullable بنظرة سريعة

النوعيُبقيمثالالنتيجة
Exclude<T, U>أعضاء T غير القابلة للإسناد إلى UExclude<"a" | "b" | "c", "a">"b" | "c"
Extract<T, U>أعضاء T القابلة للإسناد إلى UExtract<"a" | "b" | "c", "a" | "z">"a"
NonNullable<T>كل شيء عدا null وundefinedNonNullable<string | null | undefined>string

العبارة المفتاحية هي «قابل للإسناد إلى U». لا يلزم أن يكون U قائمة بأعضاء محددة؛ يمكن أن يكون نوعًا أوسع تناسبه عدة أعضاء:

اختيار أعضاء union حسب الشكل

على discriminated union، يستخرج Extract مع شكل جزئي المتغيرات التي تملكه. وهذه هي الطريقة المعتادة لتسمية متغير واحد من union لم تكتبه بنفسك:

الشكل { type: "click" } نوع أعلى (supertype) لمتغير click وحده، فهو ما يُبقيه Extract. أما الشكل الذي يطابق عدة متغيرات (مثل { x: number } لو كان في اثنين منها) فيُبقيها كلها.

NonNullable

NonNullable<T> هو نسخة الأنواع من فحص !== null && !== undefined. ويظهر عندما تشتق نوعًا من شيء اختياري:

User["manager"] هو { name: string } | null | undefined (علامة ? تضيف undefined)، ويزيل NonNullable الاثنين. ومنذ TypeScript 5.5 يستنتج المترجم هذا المسند (predicate) بنفسه، فيكون raw.filter((s) => s != null) من النوع string[] أصلًا؛ أما s is NonNullable<typeof s> الصريح فيُبقي النية واضحة ويعمل في الإصدارات الأقدم. تعريفه type NonNullable<T> = T & {}: نوع الكائن الفارغ {} يقبل كل قيمة عدا null وundefined، فالـ intersection معه يحذفهما بالضبط.

كيف تُبنى

Exclude وExtract نوعان شرطيان من سطر واحد في المكتبة القياسية:

type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;

عندما يكون T من نوع union، يُطبَّق النوع الشرطي على كل عضو منفصلًا (يتوزع)، وتختفي الأعضاء never من النتيجة. لذا يصبح Exclude<"a" | "b", "a"> هو ("a" extends "a" ? never : "a") | ("b" extends "a" ? never : "b")، أي never | "b"، أي "b". تشرح صفحة الأنواع الشرطية التوزيع بالتفصيل.

Exclude مقابل Omit، وExtract مقابل Pick

من السهل الخلط بين الأسماء لأن كلا الزوجين «يحذف» شيئًا أو «يُبقيه». والفرق فيما تعمل عليه:

يعمل علىيحذف أو يُبقيمثال
Exclude<T, U>unionأعضاء unionExclude<"a" | "b", "a"> → "b"
Extract<T, U>unionأعضاء unionExtract<"a" | "b", "a"> → "a"
Omit<T, K>نوع كائنالخصائصOmit<User, "password">
Pick<T, K>نوع كائنالخصائصPick<User, "name">

استخدام Exclude على نوع كائن زلّة شائعة، وتفشل بصمت:

Account غير قابل للإسناد إلى "password"، فيُبقيه Exclude كاملًا. وOmit نفسه مبني من Exclude مطبَّقًا على المفاتيح: Omit<T, K> هو Pick<T, Exclude<keyof T, K>>. راجع Omit للمزيد.

Exclude أكثر صرامة

يقبل المعامل الثاني لـ Exclude أي نوع، فالخطأ الإملائي لا يحذف شيئًا ولا يثير أي خطأ. إضافة قيد تجعل المترجم يتحقق من أن ما تستبعده موجود فعلًا في union:

index.ts(7,37): error TS2344: Type '"drafft"' does not satisfy the constraint 'Status'.

صحّح الإملاء فيُترجم الكود، ويكون Strict مساويًا لـ "published" | "archived". والحيلة نفسها تعمل مع Extract ومع Omit صارم (K extends keyof T).

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

ماذا يفعل Exclude في TypeScript؟

يحذف Exclude<T, U> من union T كل عضو قابل للإسناد إلى U. فـ Exclude<"a" | "b" | "c", "a"> هو "b" | "c". ولحذف عدة أعضاء مرّر union كـ U: Exclude<T, "a" | "b">.

ما الفرق بين Exclude وExtract؟

هما متعاكسان. يُبقي Exclude<T, U> أعضاء T غير القابلة للإسناد إلى U؛ ويُبقي Extract<T, U> الأعضاء القابلة لذلك فقط. ومع T وU نفسيهما، تكوّن النتيجتان معًا T.

ما الفرق بين Exclude وOmit؟

يعمل Exclude على نوع union ويحذف أعضاءه. ويعمل Omit على نوع كائن ويحذف خصائص. Exclude<User, "password"> لا يفعل شيئًا مفيدًا (يعيد User)، بينما يعطي Omit<User, "password"> نوع الكائن دون تلك الخاصية. وOmit مبني على Exclude: يستبعد المفتاح من keyof T.

ماذا يفعل NonNullable في TypeScript؟

يحذف NonNullable<T> القيمتين null وundefined من نوع: NonNullable<string | null | undefined> هو string. وهو معرّف كـ T & {}، لأن {} يقبل كل قيمة عدا null وundefined.

لماذا لا يبلّغ Exclude عن خطأ لعضو غير موجود؟

معامله الثاني غير مقيّد، فيُقبل أي نوع، وخطأ إملائي مثل Exclude<Status, "drafft"> لا يحذف شيئًا بصمت. عرّف نسخة أكثر صرامة، type StrictExclude<T, U extends T> = Exclude<T, U>، ليتحقق المترجم من أن U جزء من T.

Coddy programming languages illustration

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

ابدأ الآن