لماذا العمل مع الملفات في TypeScript ليس مخيفًا بل مريحًا
\n\nعندما بدأت الكتابة بلغة TypeScript، كنت خائفًا من فكرة: «وماذا عن الملفات؟ في المتصفح الأمر بسيط، لكن هنا — خادم، أقراص، مسارات...». ولكن، كما اتضح، العمل مع الملفات ونظام الملفات في TypeScript يشبه تجميع لعبة LEGO: هناك قطع واضحة (وحدات fs و path)، وهناك تعليمات (الأنماط)، والنتيجة متوقعة. لا مفاجآت، فقط كود نظيف.
في هذه المقالة، سنتعلم كيفية قراءة وكتابة وإعادة تسمية وحذف الملفات باستخدام TypeScript الحديث لـ Node.js. ستعرف لماذا يجب استخدام fs/promises بدلاً من fs القديم، وكيف لا تتوه في المسارات، وكيف تتعامل مع الأخطاء بشكل أنيق. هيا بنا!
التحضير: ما تحتاج معرفته قبل البدء
\n\nقبل الغوص في الكود، تأكد من تثبيت Node.js (الإصدار 14+ — حيث يوجد دعم أصلي للـ promises). وأنشئ مشروعًا بسيطًا:
\n\nmkdir ts-files-demo\ncd ts-files-demo\nnpm init -y\nnpm install typescript @types/node --save-dev\nnpx tsc --init\n\nفي ملف tsconfig.json، تأكد من تفعيل "module": "NodeNext" أو "ESNext" و "target": "ES2022". الآن أنت جاهز لـ العمل مع نظام الملفات في TypeScript.
الاستيرادات التي ستفيدك دائمًا
\n\nالطريقة الأصح لاستيراد الوحدات للعمل مع الملفات اليوم هي:
\n\nimport { readFile, writeFile, unlink, mkdir, access } from 'fs/promises';\nimport { join, dirname, basename, extname } from 'path';\nimport { fileURLToPath } from 'url';\n\nلاحظ: نحن لا نستخدم fs مع الـ callbacks. فقط fs/promises — هذا هو المعيار الحديث الذي يتناسب تمامًا مع async/await وأنماط TypeScript.
قراءة ملف: من البسيط إلى الآمن
\n\nلنبدأ بالكلاسيكيات — نقرأ ملفًا نصيًا. لنفترض أن لدينا data.txt بمحتوى ما.
import { readFile } from 'fs/promises';\n\nasync function readTextFile(filePath: string): Promise<string> {\n try {\n const content = await readFile(filePath, 'utf-8');\n return content;\n } catch (error) {\n console.error('خطأ في قراءة الملف:', error);\n throw error;\n }\n}\n\n// الاستخدام\nconst data = await readTextFile('./data.txt');\nconsole.log(data);\n\nبسيط، أليس كذلك؟ لكن في المشاريع الحقيقية، غالبًا ما نعمل مع JSON. لنصنع دالة عامة باستخدام Generics:
\n\nimport { readFile } from 'fs/promises';\n\nasync function readJsonFile<T>(filePath: string): Promise<T> {\n const raw = await readFile(filePath, 'utf-8');\n return JSON.parse(raw) as T;\n}\n\n// مثال: نقرأ ملف الإعدادات\ninterface Config {\n port: number;\n dbUrl: string;\n}\n\nconst config = await readJsonFile<Config>('./config.json');\nconsole.log(config.port); // النوع number — TypeScript سيخبرك تلقائيًا\n\nهذا هو العمل مع الملفات في TypeScript بأفضل صورة: الأنماط تحميك من الأخطاء السخيفة، والكود يبقى مقروءًا.
\n\nالكتابة إلى ملف: إنشاء وتحديث البيانات
\n\nالآن سنتعلم حفظ المعلومات. الدالة writeFile تعيد كتابة الملف إذا كان موجودًا، أو تنشئ ملفًا جديدًا.
import { writeFile, mkdir } from 'fs/promises';\nimport { dirname } from 'path';\n\nasync function saveToFile(filePath: string, data: string): Promise<void> {\n // أولاً نتأكد من وجود المجلد\n const dir = dirname(filePath);\n await mkdir(dir, { recursive: true });\n\n // الآن نكتب\n await writeFile(filePath, data, 'utf-8');\n console.log(`تم حفظ الملف ${filePath} بنجاح`);\n}\n\n// حفظ كائن بصيغة JSON\nconst user = { name: 'آنا', age: 28, role: 'admin' };\n