مقدمة: لماذا يزعج سؤال @types/* حتى المطورين ذوي الخبرة؟
هل سبق لك أن أمضيت ساعة في تصحيح خطأ تبين في النهاية أنه ناتج عن وضع حزمة @types/* بشكل خاطئ في package.json؟ إذا كان الأمر كذلك، فأنت لست وحدك. سؤال «How do I decide whether @types/* goes into dependencies or devDependencies?» حصد آلاف المشاهدات على Stack Overflow وأصبح صداعًا حقيقيًا لمجتمع TypeScript.
قد يبدو الأمر بسيطًا؟ ضع الأنواع في devDependencies وانتهى الأمر. لكن الأمر ليس بهذه السهولة. عندما يبدأ مشروعك في النمو، وتتصل المكتبات الخارجية، والمستودعات الأحادية (monorepos) وخطوط أنابيب CI/CD، فإن وضع الأنواع بشكل غير صحيح يمكن أن يؤدي إلى أخطاء بناء قاتلة، أو أعطال غير متوقعة في الإنتاج، أو الأسوأ من ذلك، فقدان صامت للكتابة (typing).
في هذه المقالة، سنستعرض أهم 5 أخطاء شائعة عند العمل مع @types/*، ونتعلم كيفية اتخاذ القرار الصحيح بناءً على سيناريوهات حقيقية، ونضع قائمة مراجعة تحميك من المشاكل. هل أنت مستعد؟ لنبدأ!
الخطأ رقم 1: «جميع @types/* تكون دائمًا في devDependencies» — خرافة تحطم عمليات البناء
أشهر نصيحة على الإنترنت تقول: «الأنواع ليست كود تشغيل (runtime)، لذا يجب أن تكون دائمًا في devDependencies». وهذا صحيح في 90% من الحالات. لكن هناك استثناء مهم ينساه الكثيرون.
متى يكون devDependencies هو الخيار الصحيح
إذا كنت تكتب تطبيقًا (خادم ويب باستخدام Express، واجهة أمامية React، أداة سطر أوامر)، فضع جميع @types/* بثقة في devDependencies. المستخدم النهائي لا يقوم بتجميع TypeScript — بل يشغل JavaScript المُجمَّع بالفعل. الأنواع تحتاجها فقط أثناء التطوير.
// مثال لتطبيق Express{ "devDependencies": { "@types/express": "^4.17.21", "@types/node": "^20.11.0", "typescript": "^5.3.3" }}متى يكون devDependencies خطأً قاتلاً
تخيل الآن: أنت تطور مكتبة تقوم بتصدير أنواع TypeScript للمستهلكين الخارجيين. إذا كانت أنواع مكتبتك تعتمد على @types/express، وقمت بوضعه في devDependencies، فإن المستخدم الذي يقوم بتثبيت مكتبتك لن يحصل على هذه الأنواع تلقائيًا. وستبدأ بيئة التطوير المتكاملة (IDE) الخاصة به في إظهار خطوط حمراء.
// ❌ خطأ للمكتبة التي تصدر أنواعًا{ "devDependencies": { "@types/express": "^4.17.21" // المستخدم لن يرى هذه الأنواع! }}
// ✅ صحيح{ "dependencies": { "@types/express": "^4.17.21" // الأنواع ستكون متاحة للمستهلكين }}القاعدة الذهبية: إذا كانت مكتبتك تعيد تصدير أنواعًا من حزمة @types/* أو تستخدمها في واجهة برمجة التطبيقات العامة (public API)، فيجب أن تكون هذه الحزمة في dependencies. إذا كانت الأنواع تُستخدم داخليًا فقط — فضعها في devDependencies.
الخطأ رقم 2: تجاهل الفرق بين «أستخدمه في الكود» و«أستخدمه في الأنواع»
كثير من المطورين يخلطون: «أنا أستورد Request من express، إذن express يجب أن يكون في dependencies». هذا صحيح بالنسبة للحزمة نفسها express، ولكن ليس لأنواعها.
دعنا نوضح بمثال محدد. هناك ثلاثة سيناريوهات لاستخدام حزمة @types/lodash:
- السيناريو أ: تكتب
import _ from 'lodash'وتستخدم_.chunk(). الأنواع مطلوبة فقط للتجميع —devDependencies. - السيناريو ب: تنشئ دالة
function mySort(arr: T[]): T[]وتستخدم داخلها_.orderBy. الأنواع لا تخرج إلى الخارج —devDependencies. - السيناريو ج: تكتب
export function proc