خطأ Type 'string' is not assignable to type في TypeScript: شرح وحلول

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

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

ابدأ الدورة

«Type 'string' is not assignable to type» — ما هو ولماذا أنت هنا؟

\n\n

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

\n\n
Type 'string' is not assignable to type 'SomeType'.
\n\n

هذا الخطأ هو بمثابة «تحية» من النظام النوعي الصارم. قد يخيف المبتدئين، لكنه في الحقيقة أفضل صديق للمطور. في هذا المقال، سنشرح لماذا يظهر خطأ Type 'string' is not assignable to type، وكيفية إصلاحه، وما هي أفضل الطرق للتعامل مع string literal types وunion types وgenerics. المقال مخصص للموقع التعليمي pythonlib.ru، لكن الأمثلة مكتوبة بلغة TypeScript.

\n\n

1. جذر المشكلة: لماذا يعترض TypeScript على السلاسل النصية؟

\n\n

TypeScript هي طبقة فوق JavaScript تضيف الكتابة النوعية الثابتة (static typing). عندما تكتب:

\n\n
let role: 'admin' | 'user' = 'admin';\nrole = 'moderator'; // خطأ: Type '"moderator"' is not assignable to type '"admin" | "user"'\n
\n\n

يفهم TypeScript أن المتغير role يمكنه قبول قيمتين فقط: 'admin' أو 'user'. عندما تحاول تعيين 'moderator'، يظهر الخطأ. لكن لماذا يكتب «Type 'string' is not assignable to type»؟

\n\n

السبب هو أن القيمة النصية 'moderator' لها نوع string، بينما النوع المتوقع هو 'admin' | 'user'. TypeScript يقارن الأنواع، وليس القيم. يرى: «أنت تعطيني سلسلة نصية عادية، وأنا أنتظر سلاسل محددة». من هنا تأتي الرسالة.

\n\n

1.1. مثال بسيط للفهم

\n\n

لننظر إلى حالة أساسية:

\n\n
type Status = 'active' | 'inactive';\n\nfunction updateStatus(status: Status) {\n  console.log(status);\n}\n\nconst myStatus = 'active';\nupdateStatus(myStatus); // صحيح\n\nconst anotherStatus = 'pending';\nupdateStatus(anotherStatus); // خطأ: Type 'string' is not assignable to type 'Status'\n
\n\n

في الحالة الأخيرة، يُستنتج أن المتغير anotherStatus من النوع string، وليس 'pending'. TypeScript لا يعرف أن 'pending' هو قيمة حرفية (literal). يرى فقط النوع string. يمكن إصلاح ذلك بتحديد النوع صراحة:

\n\n
const anotherStatus: 'pending' = 'pending'; // الآن يعمل\n
\n\n

2. مقارنة الحلول: كيفية تجنب أو إصلاح الخطأ

\n\n

هناك عدة طرق للتعامل مع خطأ Type 'string' is not assignable to type. سنقارنها من حيث البساطة والأمان والأداء.

\n\n

2.1. الحل الأول: as const — تجميد القيمة الحرفية

\n\n

الطريقة الأكثر أناقة هي استخدام as const. إنها «تجمّد» القيمة كنوع حرفي:

\n\n
const myStatus = 'active' as const;\nupdateStatus(myStatus); // صحيح\n
\n\n

المزايا: بسيط، قابل للقراءة، آمن.
\nالعيوب: يعمل فقط مع const، وليس مع let.

\n\n

2.2. الحل الثاني: Type Assertion (as) — التحويل الصريح

\n\n

يمكنك إخبار TypeScript: «أنا أعرف ما أفعله»:

\n\n
const someString: string = 'active';\nupdateStatus(someString as Status); // صحيح\n
\n\n

المزايا: حل سريع.
\nالعيوب: أنت تعطّل التحقق من الأنواع. إذا مررت قيمة خاطئة، سيظهر الخطأ فقط في وقت التشغيل (runtime).

\n\n

2.3. الحل الثالث: Type Guard (حارس النوع)

\n\n

نكتب دالة تتحقق مما إذا كانت السلسلة النصية حالة صالحة:

\n\n
function isStatus(value: string): value is Status {\n  return value === 'active' || value === 'inactive';\n}\n\nfunction safeUpdate(value: string) {\n  if (isStatus(value)) {\n    updateStatus(value); // TypeScript يعرف أن value من النوع Status\n  } else {\n    throw new Error('حالة غير صالحة');\n  }\n}\n

المدونات

توصيات الكتب