تخطّى إلى المحتوى الرئيسي
تشغيل TypeScript مباشرة في Node.js: كيف استغنينا عن خطوة البناء للسكربتات

تشغيل TypeScript مباشرة في Node.js: كيف استغنينا عن خطوة البناء للسكربتات

July 31, 2026
أدوات المطورين
5 دقيقة قراءة

أبرز النقاط

- يشغّل Node.js الآن ملفات .ts مباشرة عبر إزالة التعليقات النوعية (type stripping) عند التحميل. الميزة مفعّلة افتراضيًا منذ Node.js 23.6 ومتوفرة في إصدار LTS رقم 22.18.

- تغطي إزالة الأنواع الصياغة القابلة للمحو فقط. أما enum و namespace الذي يحتوي على كود تنفيذي وخصائص المُنشئ فتحتاج إلى العلم --experimental-transform-types.

- لا يفحص Node.js الأنواع إطلاقًا ولا يقرأ ملف tsconfig.json. يبقى فاحص الأنواع لدينا هو tsc --noEmit مفروضًا في خط CI.

- خيار erasableSyntaxOnly في TypeScript 5.8 يحوّل أي صياغة غير قابلة للمحو إلى خطأ ترجمة، فيضمن أن أي ملف يجتاز فحصنا سيعمل تحت Node.js.

- الأطر المعتمدة على الديكوريتر مثل NestJS تعتمد على emitDecoratorMetadata وهو ما لا توفره إزالة الأنواع — لذلك احتفظت خدمات NestJS لدينا بخطوة البناء.

هل يستطيع Node.js تشغيل TypeScript دون خطوة بناء؟

نعم. منذ Node.js 22.6 خلف العلم --experimental-strip-types، وافتراضيًا منذ Node.js 23.6، ينفّذ Node ملفات TypeScript عبر استبدال التعليقات النوعية بمسافات فارغة قبل التنفيذ. وجلب إصدار 22.18 هذا السلوك الافتراضي إلى خط LTS، بينما يعمل الأمر node script.ts مباشرة في Node.js 24 وهو إصدار LTS الحالي الذي ننشر عليه.

لأن الأنواع تُستبدل بمسافات بدل حذفها، تتطابق أرقام الأسطر والأعمدة في تتبّع الأخطاء مع الملف الأصلي تمامًا دون الحاجة إلى source maps. وفي وقت التشغيل يُرجع process.features.typescript القيمة 'strip' أو 'transform' أو false، وبذلك تتحقق سكربتاتنا من توفر الميزة قبل الاعتماد عليها.

في Devya بدأنا بنقل السكربتات الداخلية وملفات إعداد قواعد البيانات والمهام المجدولة إلى التشغيل المباشر، فهذه أكثر الأماكن التي كانت خطوة البناء تؤذينا فيها: كل أداة صغيرة كانت تتطلب إما ترجمة مسبقة أو اعتمادية مثل ts-node أو tsx.

ما الصياغة التي لا تدعمها إزالة الأنواع؟

الصياغة القابلة للمحو هي أي تركيب في TypeScript يمكن حذفه دون تغيير سلوك التشغيل: التعليقات النوعية والواجهات interfaces والأسماء البديلة للأنواع والأنواع العامة generics و satisfies وتحويلات as. كل ذلك تتعامل معه إزالة الأنواع.

أربعة تراكيب تولّد كود JavaScript فعليًا وبالتالي ليست قابلة للمحو: enum و namespace الذي يحمل قيمًا تنفيذية وخصائص المُنشئ و import x = require(). تشغيل ملف يستخدمها يتطلب --experimental-transform-types الذي ينقل Node.js من الإزالة إلى تحويل كامل مبني على SWC مع source maps.

يتجنب فريقنا علم التحويل كليًا. استبدلنا enum بمصفوفات ثابتة مع أنواع اتحاد مشتقة منها، وهي قابلة للمحو وأسهل في التسلسل وخالية من الكائنات التنفيذية المفاجئة التي تولّدها enum.

كيف نضمن بقاء الكود قابلاً للمحو؟

أضاف TypeScript 5.8 خيار erasableSyntaxOnly. مع تفعيله يصبح أي تركيب غير قابل للمحو خطأ ترجمة، فيفرض فاحص الأنواع نفسه التوافق مع Node.js. ونقرنه بخيار verbatimModuleSyntax الذي يُلزم كتابة استيراد الأنواع بصيغة import type ويمنع أن تغيّر إزالةُ استيرادٍ ما شكلَ شجرة الوحدات.

تفصيلان إضافيان مهمان: يجب كتابة الامتداد .ts صراحة في الاستيرادات النسبية لأن Node.js لا يعيد كتابة المسارات، لذا ينتمي allowImportingTsExtensions إلى الإعدادات. كما أن Node.js نفسه لا يقرأ tsconfig.json أبدًا؛ فالملف موجود من أجل المحرر و tsc لا من أجل وقت التشغيل.

أين يحدث فحص الأنواع إذا كان Node يزيلها؟

لا مكان له في وقت التشغيل. يتجاهل Node.js الأنواع دون النظر إليها، وهي المقايضة نفسها التي قدّمتها أدوات مبنية على esbuild مثل tsx منذ سنوات. نشغّل tsc --noEmit كبوابة في CI ومحليًا في خطاف pre-commit، ويظل المحرر يعرض الأخطاء عبر خادم لغة TypeScript. الملف الذي يحوي خطأً نوعيًا سيعمل رغم ذلك — البوابة لا وقت التشغيل هي ما يمنعه من الوصول إلى الإنتاج.

أي أداة ينبغي أن تشغّل TypeScript في 2026؟

- الإزالة الأصلية للأنواع: صفر اعتماديات، لا فحص أنواع، صياغة قابلة للمحو فقط. خيارنا الافتراضي للسكربتات والإعدادات والمهام المجدولة على Node.js 22.18 فما فوق.

- tsx: اعتمادية إضافية، لا فحص أنواع، يدعم JSX وأسماء المسارات البديلة في tsconfig. نبقيه فقط حيث تفرضه المسارات البديلة أو إصدارات Node.js الأقدم.

- ts-node: اعتمادية مع وضع فحص أنواع اختياري وإقلاع أبطأ. لم نعد نضيفه إلى المشاريع الجديدة.

- بناء tsc: فحص أنواع كامل مع إخراج ملفات التصريحات. يبقى الجواب الصحيح الوحيد للمكتبات المنشورة والتطبيقات كثيفة الديكوريتر.

أي المشاريع ينبغي أن تحتفظ بخطوة البناء؟

احتفظت خدمات NestJS لدينا بخطوتها. يعتمد حقن الاعتماديات في NestJS على emitDecoratorMetadata، ولا يوفر وضع الإزالة ولا وضع التحويل هذه البيانات الوصفية، لذا فالتشغيل المباشر ليس خيارًا هناك. ملفات JSX خارج النطاق أيضًا، ولا يحل Node.js أسماء المسارات البديلة في tsconfig، ولا تُزال الأنواع داخل node_modules أبدًا — فأي حزمة تُنشر على npm يجب أن تشحن JavaScript مترجمًا مع ملفات التصريحات.

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

**س:** هل ما زلنا بحاجة إلى ts-node أو tsx؟

**ج:** ليس للسكربتات ذات الصياغة القابلة للمحو على Node.js 22.18 أو أحدث. يبقى tsx مفيدًا لملفات JSX وأسماء المسارات البديلة وإصدارات Node.js الأقدم.

**س:** هل يفحص Node.js أنواع الملفات التي يشغّلها؟

**ج:** لا. تتجاهل إزالة الأنواع التعليقات دون التحقق منها. شغّل tsc --noEmit في CI لالتقاط أخطاء الأنواع قبل النشر.

**س:** هل يقرأ Node.js ملف tsconfig.json؟

**ج:** لا. يتجاهله وقت التشغيل كليًا في وضعي الإزالة والتحويل. يخص tsconfig.json المحرر و tsc فقط.

**س:** هل يمكننا استخدام enum مع التشغيل المباشر؟

**ج:** فقط خلف --experimental-transform-types. نوصي بدلاً من ذلك بأنماط الكائنات أو المصفوفات الثابتة مع أنواع اتحاد مشتقة — فهي قابلة للمحو وسلوكها متوقع.

**س:** هل تعمل ملفات TypeScript داخل node_modules؟

**ج:** لا. يرفض Node.js عمدًا إزالة الأنواع داخل node_modules، لذا يجب أن تشحن الحزم المنشورة JavaScript.