مقدمة: عندما يقول المترجم «لا»
\nتفتح محررك المفضل، وتكتب بضعة أسطر من كود TypeScript، وتشغل عملية البناء — وفجأة ترى هذا: 'React' refers to a UMD global, but the current file is a module. إذا سبق لك أن واجهت هذا الخطأ، فأنت تعلم كم يمكن أن يكون محبطًا. يبدو كل شيء صحيحًا: الاستيراد موجود، React مثبتة، لكن المترجم يرفض بعناد فهم ما تريده منه.
هذا الخطأ ليس مجرد خلل عشوائي. إنه يكشف عن آليات عميقة في عمل TypeScript وأنظمة البناء وتنسيقات الوحدات. في هذه المقالة، لن نعرض فقط كيفية إصلاحه. سننظر «تحت الغطاء» ونفهم لماذا يحدث خطأ React refers to a UMD global، وكيف يميز TypeScript بين UMD و ESM، وكيفية إعداد مشروعك بشكل صحيح لتنسى هذا الخطأ إلى الأبد.
\n\nالمقالة موجهة للمطورين الذين هم على دراية بالفعل بـ React و TypeScript، لكنهم يريدون فهم التفاصيل الداخلية. هل أنت مستعد؟ هيا بنا!
\n\nما هو UMD ولماذا يعرفه TypeScript؟
\n\nقبل تحليل الخطأ، دعنا نتذكر ما هي تنسيقات الوحدات في JavaScript. عندما تكتب import React from 'react'، يجب على TypeScript أن يفهم من أين يأتي هذا الكود وكيفية استخدامه. هناك عدة معايير:
- \n
- ESM (ECMAScript Modules) — المعيار الحديث الذي يستخدم
import/export. \n - CommonJS — تنسيق Node.js مع
require/module.exports. \n - UMD (Universal Module Definition) — هجين يعمل في المتصفح (عبر المتغيرات العامة) وفي Node.js (عبر الوحدات). \n
يتم توزيع React بعدة تنسيقات، بما في ذلك UMD. عندما تقوم بتثبيت React عبر npm، تحصل على نسخة ESM (مثل index.js مع export default). لكن الإصدارات القديمة أو بعض التجميعات قد تستخدم UMD، حيث تكون React متاحة كمتغير عام window.React.
يقوم TypeScript بتحليل ملفات تعريف الأنواع (.d.ts). بالنسبة لـ React، هذه هي الحزمة @types/react. بداخلها يوجد تعريف يشير إلى: «React متاحة كـ UMD عام». عندما يرى TypeScript أن ملفك مُعلّم كوحدة (على سبيل المثال، يحتوي على import أو export)، يبدأ في الارتباك: «أنت تستورد React، لكن التعريف يقول إنها عامة. والملف هو وحدة. ماذا أفعل؟»
لماذا يحدث الخطأ: «React refers to a UMD global, but the current file is a module»؟
\n\nيظهر الخطأ عندما لا يستطيع TypeScript تحديد كيفية معالجة استيراد React بشكل قاطع. إليك سيناريو نموذجي:
\n\n// App.tsx\nimport React from 'react';\nimport { useState } from 'react';\n\nconst App: React.FC = () => {\n const [count, setCount] = useState(0);\n return <div>{count}</div>;\n};\n\nexport default App;\n\n\nتقوم بتشغيل التجميع، ويصدر TypeScript الخطأ: 'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
لماذا؟ لأنه في @types/react يوجد هذا التعريف (مبسطًا):
// في ملف index.d.ts من @types/react\nexport = React;\nexport as namespace React;\n\ndeclare namespace React {\n // ...الأنواع\n}\n\n\nالسطر الرئيسي هو export as namespace React. يخبر هذا TypeScript: «هذه الوحدة متاحة أيضًا كمتغير عام React (UMD)». عندما يكون ملفك وحدة (يحتوي على export)، قد لا يفهم TypeScript ما إذا كنت تريد استخدام React العام أو المستورد. والنتيجة هي تعارض.
كيفية الإصلاح: ثلاث طرق مجربة
\n\nالطريقة 1: الاستيراد الصريح (الأكثر شيوعًا)
\n\nأبسط طريقة هي التأكد من أنك تستورد React بشكل صريح، حتى لو