خطأ TypeScript string | undefined: كيفية إصلاحه دون أن تفقد صوابك

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: «Type 'string | undefined' is not assignable to type 'string'» — ألم مألوف؟

\n\n

إذا كنت تكتب بلغة TypeScript لمدة أسبوع على الأقل، فمن المؤكد أنك رأيت هذه الرسالة. تظهر في أكثر اللحظات غير المتوقعة: أنت متأكد أن المتغير هو سلسلة نصية، ولكن المترجم يصر بعناد: «مهلاً، قد يكون هناك undefined!». هل هذا مألوف؟

\n\n

هذا الخطأ هو أحد أكثر الأسئلة شيوعًا على Stack Overflow (آلاف المشاهدات، عشرات الإجابات). والمسألة ليست أن TypeScript «غبي». بل على العكس: إنه ينقذك من أخطاء وقت التشغيل التي قد تعطل التطبيق. ولكن كيف تشرح ذلك للمترجم؟ كيف تجعل الكود آمنًا وقابلاً للقراءة في نفس الوقت؟

\n\n

في هذه المقالة، سنحلل:

\n
    \n
  • لماذا يحدث خطأ Type 'string | undefined' is not assignable to type 'string'
  • \n
  • 5 طرق عملية لإصلاحه (من البسيط إلى المتقدم)
  • \n
  • المزالق النموذجية للمبتدئين
  • \n
  • متى تستخدم ! (non-null assertion)، ومتى يكون ?? (nullish coalescing) أفضل
  • \n
\n\n

هل أنت مستعد؟ هيا بنا!

\n\n

1. لماذا يحدث هذا الخطأ في TypeScript؟

\n\n

في JavaScript، يمكن أن يكون المتغير undefined في أي لحظة. TypeScript، خاصة مع تفعيل العلم strictNullChecks، يريد منك أن تحدد بوضوح: «أنا أعلم أنه قد يكون هناك قيمة فارغة هنا، وأنا أتعامل معها».

\n\n

انظر إلى هذا المثال البسيط:

\n\n
function getUsername(id: number): string {\n    const user = users.find(u => u.id === id);\n    return user.name; // خطأ! user قد يكون undefined\n}\n
\n\n

الطريقة find() تُرجع User | undefined. إذا لم يتم العثور على المستخدم، فستُرجع undefined. TypeScript يرى هذا ويصرخ: «أنت تحاول تعيين string | undefined إلى string! لا يمكن!».

\n\n

هذا ليس خطأ في TypeScript، بل هو ميزة. إنه يجبرك على التفكير: «ماذا لو لم يكن المستخدم موجودًا؟ ماذا سترجع الدالة؟ سلسلة نصية فارغة؟ ستلقي خطأ؟». وهذا صحيح.

\n\n

2. 5 طرق لإصلاح الخطأ (من البسيط إلى المعقد)

\n\n

2.1. عامل التأكيد على عدم القيمة الخالية (!)

\n\n

أسرع طريقة (والأكثر خطورة) هي أن تقول لـ TypeScript: «اخرس، أنا أعرف ما أفعله».

\n\n
function getUsername(id: number): string {\n    const user = users.find(u => u.id === id);\n    return user!.name; // ! — أنا متأكد أن user ليس undefined\n}\n
\n\n

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

\n

متى لا تستخدمه: في 90% من الحالات. هذا يشبه إيقاف تشغيل الوسادة الهوائية في السيارة - إنه يعمل، لكن المخاطرة هائلة.

\n\n

2.2. التحقق عبر if (حارس النوع)

\n\n

طريقة كلاسيكية وآمنة:

\n\n
function getUsername(id: number): string {\n    const user = users.find(u => u.id === id);\n    if (user) {\n        return user.name; // TypeScript يعلم: داخل الكتلة user هو بالتأكيد User\n    }\n    return 'ضيف'; // قيمة احتياطية\n}\n
\n\n

TypeScript ذكي: بعد التحقق if (user) فإنه «يضيق» النوع. داخل الكتلة، user هو User، وليس User | undefined.

\n\n

2.3. عامل السلسلة الاختياري (?.) مع قيمة احتياطية

\n\n

سطر واحد أنيق للعمل مع الكائنات المتداخلة:

\n\n
function getUsername(id: number): string {\n    const user = users.find(u => u.id === id);\n    return user?.name ?? 'ضيف';\n}\n
\n\n

دعنا نحلله بالتفصيل:

\n
    \n
  • user?.name — إذا كان user هو undefined، فإنه يُرجع undefined دون التسبب في خطأ
  • \n
  • ?? 'ضيف' — إذا كانت القيمة على اليسار undefined أو null، نستخدم 'ضيف'
  • \

المدونات

توصيات الكتب