مقدمة: لماذا نحتاج العمل مع نظام الملفات في TypeScript؟
\n\nكل تطبيق عاجلاً أم آجلاً يحتاج إلى التفاعل مع نظام الملفات: حفظ الإعدادات، معالجة الملفات المرفوعة، تسجيل السجلات أو إدارة المشاريع. TypeScript، كونه طبقة فوق JavaScript، يوفر للمطور أدوات قوية للعمل مع الملفات والدلائل من خلال وحدة fs (File System) من Node.js.
في هذه المقالة، سنشرح من خلال أمثلة عملية العمليات الأساسية مع نظام الملفات في TypeScript: قراءة وكتابة الملفات، إنشاء وحذف الدلائل، بالإضافة إلى معالجة الأخطاء. سيتم تقديم جميع الأمثلة باستخدام التصنيف الصارم (strict typing)، وهي الميزة الرئيسية لـ TypeScript.
\n\nالوحدات الأساسية للعمل مع نظام الملفات
\n\nقبل الانتقال إلى التطبيق العملي، دعنا نتعرف على ثلاث وحدات أساسية ستكون ضرورية للعمل:
\n\n- \n
- fs — الوحدة الأساسية لعمليات نظام الملفات (قراءة، كتابة، حذف) \n
- fs/promises — نسخة من وحدة
fsمع دعم الـ Promises (موصى بها للكود الحديث) \n - path — أداة مساعدة للعمل مع مسارات الملفات والدلائل \n
لاستيراد الوحدات في TypeScript، استخدم الصيغة التالية:
\n\nimport * as fs from 'fs';\nimport * as fsPromises from 'fs/promises';\nimport * as path from 'path';\n\nملاحظة: للعمل بشكل صحيح مع TypeScript، تأكد من تعيين الخيارات "moduleResolution": "node" و "esModuleInterop": true في ملف tsconfig.json الخاص بك.
قراءة الملفات: الطرق المتزامنة وغير المتزامنة
\n\nالقراءة المتزامنة مع التصنيف
\n\nالطرق المتزامنة تمنع تنفيذ الكود حتى اكتمال العملية. استخدمها فقط للملفات الصغيرة أو أثناء التحميل الأولي للتطبيق:
\n\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nfunction readConfigSync(): Record<string, unknown> {\n const configPath = path.join(__dirname, 'config.json');\n \n try {\n const data = fs.readFileSync(configPath, 'utf-8');\n return JSON.parse(data) as Record<string, unknown>;\n } catch (error) {\n if (error instanceof Error) {\n console.error('خطأ في قراءة الإعدادات:', error.message);\n }\n return {};\n }\n}\n\nconst config = readConfigSync();\nconsole.log('تم تحميل الإعدادات:', config);\n\nالقراءة غير المتزامنة مع async/await (الطريقة الموصى بها)
\n\nللكود الإنتاجي، استخدم دائمًا الطرق غير المتزامنة. TypeScript يعمل بشكل ممتاز مع async/await:
\n\nimport { readFile } from 'fs/promises';\nimport * as path from 'path';\n\ninterface UserData {\n id: number;\n name: string;\n email: string;\n}\n\nasync function readUserData(fileName: string): Promise<UserData[]> {\n const filePath = path.resolve('data', fileName);\n \n try {\n const rawData = await readFile(filePath, { encoding: 'utf-8' });\n const users: UserData[] = JSON.parse(rawData);\n return users;\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`تعذر قراءة الملف ${fileName}: ${error.message}`);\n }\n throw error;\n }\n}\n\n// الاستخدام\n(async () => {\n try {\n const users = await readUserData('users.json');\n console.log(`تم تحميل ${users.length} مستخدم`);\n } catch (error) {\n console.error(error);\n }\n})();\n\nكتابة وتحديث الملفات
\n\nإنشاء واستبدال الملفات
\n\nلكتابة البيانات إلى ملف، استخدم طريقة writeFile. ستقوم بإنشاء الملف إذا لم يكن موجودًا، أو استبداله إذا كان موجودًا:
import { writeFile, mkdir } from 'fs/promises';\nimport * as path from 'path';\n\ninterface LogEntry {\n timestamp: string;\n level: 'info' | 'warn' | 'error';\n message: string;\n}\n\n