value as Type تأكيد نوع (type assertion): يخبر TypeScript أن تعامل value على أنها Type. يسميه الناس تحويلًا (cast)، لكنه مجرد تعليمة للمترجم. يُحذف من ناتج JavaScript، ولا يحوّل شيئًا ولا يفحص شيئًا وقت التشغيل.
هذا هو الاستخدام المعتاد: تعرف عن قيمة ما أكثر مما يستطيع المترجم معرفته (هنا شكل بيانات JSON)، فتصرّح بذلك. إن كنت مخطئًا فلن ينبهك شيء. تبيّن الأقسام التالية ما يعنيه ذلك، ومتى يكون الفحص وقت التشغيل الخيار الأفضل.
as وصيغة الأقواس الزاوية
للتأكيد نفسه كتابتان:
const someValue: unknown = "hello";
const a = someValue as string; // as syntax
const b = <string>someValue; // angle-bracket syntax, same meaning
صيغة الأقواس الزاوية غير مسموحة في ملفات .tsx، حيث تُقرأ <string> على أنها وسم JSX. استخدم as في كل مكان ولن تواجه هذا السؤال. التأكيدات ضعيفة الارتباط، فضعها بين قوسين حين تكمل التعبير بعدها: (value as string).length.
التأكيدات لا تحوّل القيم
هذا الجزء هو ما يسبب أخطاء حقيقية. التأكيد يغيّر ما يعتقده المترجم عن القيمة، لا القيمة نفسها:
يعتقد المترجم أن asserted من نوع number، فيمر asserted + 1 في فحص الأنواع على أنه عملية حسابية. لكنها وقت التشغيل لا تزال النص "42"، فتدمج JavaScript النصين. لتغيير نوع قيمة حوّلها: Number(x)، وString(x)، وBoolean(x)، وBigInt(x)، وnew Date(x). تقارن صفحة تحويل النص إلى رقم بين دوال التحويل.
| تريد أن | اكتب | الأثر وقت التشغيل |
|---|---|---|
| تخبر المترجم بنوع تعرفه | x as T | لا شيء |
| تحوّل نصًا إلى رقم | Number(x)، parseInt(x, 10) | يحوّل |
| تحوّل أي شيء إلى نص | String(x)، `${x}` | يحوّل |
| تفحص النوع أولًا | type guard، typeof، instanceof | يفحص |
ما يسمح به المترجم
as ليست بلا حدود. تسمح TypeScript بـ x as T حين يكون أحد النوعين قابلًا للإسناد إلى الآخر: التوسيع ("a" as string، dog as Animal) والتضييق (animal as Dog، unknown as User) كلاهما مقبول. وحين لا يتداخل النوعان إطلاقًا ترفض:
يبلّغ المترجم index.ts(3,11): error TS2352: Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. الرسالة نفسها تذكر المخرج: input as unknown as number. هذا التأكيد المزدوج يُترجم بنجاح، وهو خاطئ وقت التشغيل تمامًا مثل المثال السابق. حين تشعر أنك تحتاجه، فالحل الصحيح عادة تحويل (Number(input)) أو نوع مختلف.
قاعدة التداخل متساهلة مع الكائنات. كائن literal يحتوي بعض الخصائص يُقبل، وهكذا تمرّر as الكائنات الناقصة بصمت:
توصيف النوع (const draft: User = { name: "Ada" }) أو satisfies User كان سيبلّغ عن email الناقصة (TS2741). استخدم as على كائن literal فقط حين تنوي فعلًا إكماله لاحقًا، وفضّل بناء الكائن كاملًا.
as const شيء مختلف
تبدو as const تأكيدًا، لكنها تفعل عكس التوسيع: تجعل القيمة الحرفية أضيق ما يمكن. تبقى النصوص أنواعًا حرفية، وتصبح المصفوفات tuples للقراءة فقط، وتصبح خصائص الكائنات readonly.
إنها آمنة، لأنها تصف القيمة الحرفية بدقة بدل أن تدّعي شيئًا لا يراه المترجم. (التأكيد sizes as readonly string[] داخل isSize تأكيد توسيع، وهو آمن أيضًا: يسمح لـ includes بقبول أي نص.) راجع الأنواع الحرفية للمزيد.
متى يكون الـ Type Guard الأداة الأفضل
as ادعاء، والـ type guard فحص. عند حدود البرنامج حيث تأتي البيانات من خارج الكود (JSON، وfetch، وlocalStorage، ومدخلات المستخدم، والرسائل)، قد يكون الادعاء خاطئًا، والتأكيد يحوّل خطأً واضحًا عند الحدود إلى خطأ محيّر في موضع آخر.
دليل تقريبي للأدوات المتشابهة:
| الأداة | تفحص وقت الترجمة | تفحص وقت التشغيل | استخدمها حين |
|---|---|---|---|
توصيف النوع const x: T = ... | نعم، بالكامل | لا | تبني القيمة بنفسك |
satisfies T | نعم، بالكامل، مع الحفاظ على النوع المستنتج | لا | كائنات الـ literal والإعدادات |
as T | فقط «هل يتداخل النوعان» | لا | تعرف أكثر من المترجم |
x! | تحذف null / undefined فقط | لا | تعرف أن القيمة موجودة |
Type guard x is T | جسم الـ guard كود عادي | نعم | البيانات من الخارج |
يبقى استخدامان جيدان لـ as: تضييق شيء لا يستطيع المترجم تتبعه (عنصر في Map أضفته قبل سطرين، أو قيمة من مكتبة بلا أنواع)، وكود الاختبارات الذي يبني بيانات تجريبية جزئية. اجعلها صغيرة وقريبة من الموضع الذي تعرف فيه أن الادعاء صحيح.
الأسئلة الشائعة
ماذا تفعل as في TypeScript؟
value as Type تأكيد نوع (type assertion): يخبر المترجم أن يعامل value على أنها Type من هذه النقطة. يُحذف من JavaScript الناتج، فلا يُجري أي تحويل ولا أي فحص وقت التشغيل. إذا كان التأكيد خاطئًا يفشل البرنامج لاحقًا، في أي موضع يُستخدم فيه النوع الخاطئ.
كيف أحوّل نوعًا (cast) في TypeScript؟
لا توجد في TypeScript تحويلات وقت التشغيل. استخدم as (أو الصيغة الأقدم <Type>value) لتغيير النوع الثابت حين تعرف أكثر من المترجم. ولتحويل قيمة فعلًا استدعِ دالة: Number("42")، وString(42)، وBoolean(x)، وnew Date(text).
ماذا تعني "as unknown as" في TypeScript؟
تأكيد مزدوج. ترفض TypeScript x as T حين لا يتداخل النوعان إطلاقًا (الخطأ TS2352)، والمرور عبر unknown أولًا يتجاوز هذا الفحص، لأن أي شيء يمكن تأكيده إلى unknown ومنه. إنه يعطّل فحص الأنواع لتلك القيمة كليًا، فاحتفظ به للاختبارات وللكود الذي تحققت فيه من النوع بطريقة أخرى.
ما الفرق بين as والأقواس الزاوية في TypeScript؟
لا فرق في المعنى: <string>value وvalue as string التأكيد نفسه. صيغة الأقواس الزاوية لا تُستخدم في ملفات .tsx لأنها تتعارض مع JSX، لذلك as هي الصيغة التي يستخدمها الجميع.
ما الفرق بين as وsatisfies؟
as تتجاوز النوع المستنتج وتفحص القليل جدًا (الخصائص الناقصة مسموحة). أما satisfies فتفحص القيمة مقابل نوع، وتبلّغ عن الخصائص الناقصة أو الزائدة، وتحافظ على النوع المستنتج الدقيق. فضّل satisfies لكائنات الـ literal، وas فقط حين تعرف فعلًا أكثر من المترجم.