فهم tsconfig.json
ملف tsconfig.json هو قلب تكوين مشروع TypeScript الخاص بك. إنه يتحكم في كيفية تحويل مترجم TypeScript (tsc) لشفرتك وما قواعد فحص الأنواع التي يجب فرضها. إتقان هذا التكوين أمر حاسم لتجربة تطوير مثالية وجودة شفرة عالية.
بنية التكوين الأساسية
{
"compilerOptions": {
// إعدادات المترجم
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"],
"files": ["./path/to/specific/file.ts"],
"extends": "./base-config.json",
"references": [
{ "path": "./packages/core" }
]
}
إعدادات الهدف والوحدة
هذه تحدد إصدار JavaScript ونظام الوحدات الذي يتم تجميع شفرتك إليه:
{
"compilerOptions": {
// إصدار JavaScript للتجميع إليه
"target": "ES2022", // ES3, ES5, ES6/ES2015, ES2016...ES2023, ESNext
// نظام الوحدات
"module": "ESNext", // CommonJS, AMD, UMD, System, ES2015, ES2020, ESNext, NodeNext
// استراتيجية حل الوحدات
"moduleResolution": "bundler", // node, classic, node16, nodenext, bundler
// السماح بالاستيرادات الافتراضية من الوحدات بدون تصدير افتراضي
"allowSyntheticDefaultImports": true,
// تمكين التوافق بين CommonJS ووحدات ES
"esModuleInterop": true,
// استيراد المساعدين من tslib
"importHelpers": true,
// إنشاء ملفات .d.ts المقابلة
"declaration": true,
// إنشاء ملفات sourcemap
"sourceMap": true
}
}
ملاحظة: للمشاريع الحديثة التي تستخدم Vite أو Webpack أو أدوات تجميع أخرى، استخدم "moduleResolution": "bundler" والذي يوفر أفضل تجربة للمطور مع أسماء المسارات المستعارة وصادرات package.json.
خيارات فحص الأنواع الصارمة
هذه هي الإعدادات الأكثر أهمية لسلامة الأنواع:
{
"compilerOptions": {
// تمكين جميع الفحوصات الصارمة (موصى به)
"strict": true,
// علامات صارمة فردية (مفعلة عندما strict: true)
"noImplicitAny": true, // خطأ عند استنتاج نوع 'any'
"strictNullChecks": true, // null/undefined يجب أن يكونا صريحين
"strictFunctionTypes": true, // فحص معاملات الدالة الصارم
"strictBindCallApply": true, // bind/call/apply صارم
"strictPropertyInitialization": true, // يجب تهيئة خصائص الفئة
"noImplicitThis": true, // خطأ على 'this' مع 'any' ضمني
"alwaysStrict": true, // التحليل في الوضع الصارم وإصدار "use strict"
"useUnknownInCatchVariables": true, // متغيرات catch هي 'unknown' وليس 'any'
// فحوصات صارمة إضافية
"noUnusedLocals": true, // خطأ على المتغيرات المحلية غير المستخدمة
"noUnusedParameters": true, // خطأ على معاملات الدالة غير المستخدمة
"noImplicitReturns": true, // خطأ عندما لا ترجع جميع مسارات الشفرة
"noFallthroughCasesInSwitch": true, // خطأ على حالات switch السقوط
"noUncheckedIndexedAccess": true, // إضافة undefined إلى الوصول المفهرس
"noImplicitOverride": true, // يتطلب كلمة 'override'
"noPropertyAccessFromIndexSignature": true, // يتطلب تدوين الأقواس للوصول المفهرس
"exactOptionalPropertyTypes": true // لا تسمح بـ undefined للخصائص الاختيارية
}
}
أفضل ممارسة: ابدأ المشاريع الجديدة بـ "strict": true وجميع الفحوصات الصارمة الإضافية مفعلة. هذا يلتقط الأخطاء مبكراً ويحسن جودة الشفرة بشكل كبير.
تعيين المسارات والأسماء المستعارة
تكوين أسماء المسارات المستعارة للاستيرادات الأنظف:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"],
"@types/*": ["src/types/*"],
"@config": ["src/config/index.ts"],
"~/*": ["./src/*"]
}
}
}
الآن يمكنك كتابة استيرادات نظيفة:
// بدلاً من
import { Button } from '../../../components/Button';
import { formatDate } from '../../../utils/date';
// يمكنك الكتابة
import { Button } from '@components/Button';
import { formatDate } from '@utils/date';
تحذير: تعيين المسارات يؤثر فقط على فحص أنواع TypeScript. أداة التجميع الخاصة بك (Webpack، Vite، إلخ) تحتاج إلى تكوين منفصل لحل هذه الأسماء المستعارة في وقت التشغيل.
مراجع المشروع للمستودعات الأحادية
استخدم مراجع المشروع لبناء قواعد الشفرة الكبيرة بكفاءة:
tsconfig.json الجذر:
{
"files": [],
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/utils" },
{ "path": "./packages/ui" }
]
}
packages/core/tsconfig.json:
{
"compilerOptions": {
"composite": true, // تمكين مراجع المشروع
"declaration": true, // إنشاء ملفات .d.ts
"declarationMap": true, // إنشاء ملفات .d.ts.map
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}
packages/ui/tsconfig.json (يعتمد على core):
{
"compilerOptions": {
"composite": true,
"declaration": true,
"outDir": "./dist"
},
"references": [
{ "path": "../core" }
],
"include": ["src/**/*"]
}
بناء جميع المشاريع:
# بناء جميع المشاريع المشار إليها
tsc --build
# تنظيف وإعادة البناء
tsc --build --clean
tsc --build --force
# وضع المراقبة
tsc --build --watch
خيارات المكتبة والإعلان
التحكم في تعريفات الأنواع المدمجة المتاحة:
{
"compilerOptions": {
// تحديد ملفات المكتبة المراد تضمينها
"lib": [
"ES2022", // أحدث ميزات JavaScript
"DOM", // واجهات برمجة تطبيقات المتصفح
"DOM.Iterable", // مكررات DOM
"WebWorker" // واجهات برمجة تطبيقات Web Worker
],
// تعريفات الأنواع المراد تضمينها (بدون استيرادات)
"types": [
"node", // أنواع Node.js
"jest", // أنواع Jest
"vite/client" // أنواع بيئة Vite
],
// الدلائل للبحث عن تعريفات الأنواع
"typeRoots": [
"./node_modules/@types",
"./src/types"
],
// تخطي فحص الأنواع لملفات الإعلان
"skipLibCheck": true
}
}
ملاحظة: اضبط "skipLibCheck": true في جميع المشاريع تقريباً - إنه يسرع التجميع بشكل كبير عن طريق تخطي فحص أنواع إعلانات node_modules.
خيارات الإصدار
التحكم في الملفات التي ينشئها TypeScript:
{
"compilerOptions": {
// دليل الإخراج
"outDir": "./dist",
// الدليل الجذر لملفات المصدر
"rootDir": "./src",
// إزالة التعليقات من الإخراج
"removeComments": true,
// عدم إصدار ملفات الإخراج
"noEmit": true,
// عدم الإصدار إذا حدثت أخطاء
"noEmitOnError": true,
// استيراد مساعدي الإصدار من tslib
"importHelpers": true,
// دعم JSX
"jsx": "react-jsx", // preserve, react, react-jsx, react-jsxdev, react-native
// إصدار بيانات التعريف لنوع التصميم للديكوراتورات
"emitDecoratorMetadata": true,
// تمكين الديكوراتورات التجريبية
"experimentalDecorators": true,
// الحفاظ على enums الثابتة
"preserveConstEnums": false,
// إنشاء ملف واحد لكل وحدة
"isolatedModules": true,
// إصدار BOM لملفات UTF-8
"emitBOM": false,
// حرف السطر الجديد
"newLine": "lf", // lf, crlf
// إزالة الشفرة الداخلية
"stripInternal": true
}
}
التعمق في حل الوحدات
فهم كيفية حل TypeScript للوحدات:
الاستراتيجية الكلاسيكية (مهجورة):
// استيراد: import { x } from "moduleB"
// ترتيب الحل:
1. /root/src/moduleB.ts
2. /root/src/moduleB.d.ts
3. /root/moduleB.ts
4. /root/moduleB.d.ts
5. /moduleB.ts
6. /moduleB.d.ts
استراتيجية Node (تقليدية):
// استيراد: import { x } from "moduleB"
// ترتيب الحل:
1. /root/src/node_modules/moduleB.ts
2. /root/src/node_modules/moduleB/package.json (تحقق من حقل "types")
3. /root/src/node_modules/moduleB/index.ts
4. /root/node_modules/moduleB.ts
5. ... (يستمر في شجرة الدليل)
استراتيجية Bundler (حديثة):
{
"compilerOptions": {
"moduleResolution": "bundler",
// السماح باستيراد ملفات .ts بدون امتداد
"allowImportingTsExtensions": true,
// احترام حقل "exports" في package.json
"resolvePackageJsonExports": true,
// احترام حقل "imports" في package.json
"resolvePackageJsonImports": true,
// السماح باستيرادات JSON
"resolveJsonModule": true
}
}
خيارات المترجم المتقدمة
{
"compilerOptions": {
// التجميع المتزايد
"incremental": true,
"tsBuildInfoFile": "./.tsbuildinfo",
// التشخيصات
"diagnostics": false,
"extendedDiagnostics": false,
"listEmittedFiles": false,
"listFiles": false,
// الأداء
"assumeChangesOnlyAffectDirectDependencies": true,
// توليد الشفرة
"downlevelIteration": true, // دعم for-of على أهداف أقدم
"inlineSourceMap": false,
"inlineSources": false,
"declarationMap": true,
// كشف الوحدة
"moduleDetection": "auto", // auto, legacy, force
// اكتساب النوع
"disableSizeLimit": false,
// الإسهاب
"suppressExcessPropertyErrors": false,
"suppressImplicitAnyIndexErrors": false,
// التوافق
"allowUmdGlobalAccess": false,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"forceConsistentCasingInFileNames": true
}
}
تكوين وضع المراقبة
{
"watchOptions": {
// استراتيجية المراقبة
"watchFile": "useFsEvents", // fixedPollingInterval, priorityPollingInterval,
// dynamicPriorityPolling, useFsEvents, useFsEventsOnParentDirectory
"watchDirectory": "useFsEvents",
// فترات الاستطلاع (عند استخدام الاستطلاع)
"fallbackPolling": "dynamicPriority",
"synchronousWatchDirectory": true,
// استبعاد الدلائل من المراقبة
"excludeDirectories": ["**/node_modules", "_build"],
"excludeFiles": ["build/fileWhichChangesOften.ts"]
}
}
التكوينات الخاصة بالبيئة
التكوين الأساسي (tsconfig.base.json):
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true
}
}
تكوين التطوير (tsconfig.json):
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"noEmit": true,
"incremental": true,
"sourceMap": true
},
"include": ["src/**/*", "tests/**/*"]
}
تكوين بناء الإنتاج (tsconfig.build.json):
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"removeComments": true,
"sourceMap": false
},
"include": ["src/**/*"],
"exclude": ["src/**/*.test.ts", "src/**/*.spec.ts"]
}
تكوين Node.js Native ESM
لمشاريع Node.js التي تستخدم ESM الأصلي (package.json مع "type": "module"):
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext", // أو "Node16"
"moduleResolution": "NodeNext", // أو "Node16"
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"isolatedModules": true
}
}
مع هذا التكوين، يجب عليك استخدام امتدادات الملفات الصريحة:
// ✓ صحيح
import { myFunc } from './utils.js'; // ملاحظة: .js، وليس .ts!
// ✗ خطأ
import { myFunc } from './utils';
تكوين مشروع React
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"jsx": "react-jsx", // أو "react-jsxdev" للتطوير
"moduleResolution": "bundler",
"resolveJsonModule": true,
"allowImportingTsExtensions": true,
"isolatedModules": true,
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
تصحيح مشاكل التكوين
استخدم هذه العلامات للمترجم لتشخيص المشاكل:
# إظهار جميع خيارات المترجم
tsc --showConfig
# شرح سبب تضمين الملفات
tsc --explainFiles
# إظهار آثار الحل التفصيلية
tsc --traceResolution
# سرد جميع الملفات المصدرة
tsc --listEmittedFiles
# إظهار التشخيصات الموسعة
tsc --extendedDiagnostics
# إنشاء تتبع النوع
tsc --generateTrace ./trace
تمرين:
- أنشئ بنية مستودع أحادي مع 3 حزم باستخدام مراجع المشروع
- قم بإعداد أسماء مستعارة للمسارات لـ @components و @utils و @types
- قم بتكوين ملفات tsconfig مختلفة للتطوير والإنتاج والاختبار
- قم بتمكين جميع خيارات فحص الأنواع الصارمة وإصلاح أي أخطاء
- استخدم
--explainFiles لفهم الملفات التي يتم تجميعها ولماذا