TypeScript

الدوال في TypeScript — دليل شامل Functions 2026

📅 2026-10-04⏱ 9 دقائق قراءة
في المقال السابق، تعلمت الواجهات وكيفية تعريف هياكل البيانات. الآن سنتعمق في **الدوال (Functions)** — مع إضافة قوة TypeScript المتمثلة في **الأنواع**. في هذا الدليل العملي، سنأخذك خطوة بخطوة لفهم الدوال في TypeScript، مع تمارين وحلول. ## ما هي الدالة؟ الدالة هي **كتلة من الكود** لها اسم، تؤدي مهمة محددة، ويمكن استدعاؤها عدة مرات. **مثال بسيط:** ```typescript function greet(name: string): string { return `مرحباً ${name}!`; } console.log(greet("أحمد")); // مرحباً أحمد! ``` **شرح:** - **`function`:** كلمة مفتاحية لتعريف الدالة. - **`greet`:** اسم الدالة. - **`name: string`:** المعامل مع نوعه. - **`: string`:** نوع القيمة المرجعة. - **`return ...`:** القيمة التي ترجعها الدالة. ## لماذا نستخدم الدوال؟ - **إعادة الاستخدام:** اكتب مرة، استخدم عدة مرات. - **التنظيم:** قسم البرنامج إلى أجزاء صغيرة. - **سهولة الصيانة:** عدّل في مكان واحد. - **الوضوح:** الكود يصبح أسهل للقراءة. - **الاختبار:** يمكن اختبار كل دالة على حدة. ## أنواع الدوال في TypeScript ### 1. Function Declaration — التعريف التقليدي ```typescript function add(a: number, b: number): number { return a + b; } console.log(add(5, 3)); // 8 ``` **ميزتها:** يمكن استدعاؤها قبل تعريفها (Hoisting). ### 2. Function Expression — تعبير دالة ```typescript const add = function(a: number, b: number): number { return a + b; }; console.log(add(5, 3)); // 8 ``` **الفرق:** لا يمكن استدعاؤها قبل التعريف. ### 3. Arrow Function — الدالة السهمية ```typescript const add = (a: number, b: number): number => { return a + b; }; // أو أقصر (إذا كان سطراً واحداً): const add = (a: number, b: number): number => a + b; ``` **ميزاتها:** - أقصر. - لا تحتاج `function`. - إذا كان السطر واحداً، يمكن حذف `{}` و `return`. ### 4. دالة بدون معاملات ```typescript const greet = (): string => "مرحباً!"; console.log(greet()); // مرحباً! ``` ### 5. دالة بدون قيمة مرجعة (void) ```typescript function logMessage(message: string): void { console.log(message); } logMessage("مرحباً"); // مرحباً ``` ## أنواع المعاملات ### 1. المعاملات المطلوبة ```typescript function greet(name: string, age: number): string { return `مرحباً ${name}، عمرك ${age}`; } console.log(greet("أحمد", 25)); ``` ### 2. المعاملات الاختيارية (Optional) استخدم `?` لجعل المعامل اختيارياً: ```typescript function greet(name: string, title?: string): string { if (title) { return `مرحباً ${title} ${name}`; } return `مرحباً ${name}`; } console.log(greet("أحمد")); // مرحباً أحمد console.log(greet("أحمد", "دكتور")); // مرحباً دكتور أحمد ``` **⚠️ مهم:** المعاملات الاختيارية يجب أن تكون **بعد** المعاملات المطلوبة. ```typescript // ❌ خطأ: function greet(title?: string, name: string) {} // ✅ صحيح: function greet(name: string, title?: string) {} ``` ### 3. القيم الافتراضية (Default) ```typescript function greet(name: string = "زائر"): string { return `مرحباً ${name}`; } console.log(greet()); // مرحباً زائر console.log(greet("أحمد")); // مرحباً أحمد ``` ### 4. المعاملات المتبقية (Rest Parameters) ```typescript function sum(...numbers: number[]): number { return numbers.reduce((acc, n) => acc + n, 0); } console.log(sum(1, 2, 3)); // 6 console.log(sum(1, 2, 3, 4, 5)); // 15 console.log(sum()); // 0 ``` ## أنواع القيم المرجعة ### 1. نوع محدد ```typescript function add(a: number, b: number): number { return a + b; } ``` ### 2. void — لا قيمة ```typescript function log(message: string): void { console.log(message); } ``` ### 3. never — لا يحدث أبداً ```typescript function throwError(message: string): never { throw new Error(message); } ``` ### 4. Union — عدة أنواع ```typescript function parse(value: string): number | null { const num = Number(value); return isNaN(num) ? null : num; } console.log(parse("123")); // 123 console.log(parse("abc")); // null ``` ### 5. Promise (للدوال غير المتزامنة) ```typescript async function fetchData(): Promise<string> { return "بيانات"; } ``` ## نوع الدالة (Function Type) يمكنك تعريف **نوع** للدالة: ```typescript type MathOperation = (a: number, b: number) => number; const add: MathOperation = (a, b) => a + b; const subtract: MathOperation = (a, b) => a - b; const multiply: MathOperation = (a, b) => a * b; ``` **الفائدة:** يمكن استخدام نفس النوع لعدة دوال. ## الدوال كمعاملات (Callbacks) ```typescript function processArray( arr: number[], callback: (item: number) => number ): number[] { return arr.map(callback); } const doubled = processArray([1, 2, 3], (n) => n * 2); console.log(doubled); // [2, 4, 6] const squared = processArray([1, 2, 3], (n) => n * n); console.log(squared); // [1, 4, 9] ``` ## الدوال المُرجَعة (Higher-Order Functions) الدوال التي ترجع دوالاً: ```typescript function createMultiplier(factor: number): (n: number) => number { return (n) => n * factor; } const double = createMultiplier(2); const triple = createMultiplier(3); console.log(double(5)); // 10 console.log(triple(5)); // 15 ``` ## الدوال العامة (Overloads) يمكن لدالة أن يكون لها **عدة تواقيع**: ```typescript function greet(name: string): string; function greet(names: string[]): string; function greet(value: string | string[]): string { if (Array.isArray(value)) { return `مرحباً ${value.join(", ")}`; } return `مرحباً ${value}`; } console.log(greet("أحمد")); // مرحباً أحمد console.log(greet(["أحمد", "محمد"])); // مرحباً أحمد, محمد ``` **متى تستخدمها؟** عندما تريد أن تتعامل الدالة مع أنواع مختلفة من المدخلات. ## الدوال المجهولة (Anonymous Functions) دالة بدون اسم، تُستخدم كقيمة: ```typescript const greet = function(name: string): string { return `مرحباً ${name}`; }; // أو كـ Arrow: const greet2 = (name: string): string => `مرحباً ${name}`; ``` ## الدوال العودية (Recursion) الدالة التي تستدعي نفسها: ```typescript function factorial(n: number): number { if (n <= 1) return 1; return n * factorial(n - 1); } console.log(factorial(5)); // 120 ``` **⚠️ تحذير:** تأكد من وجود **حالة توقف** (base case)، وإلا ستحدث حلقة لا نهائية. ## الدوال غير المتزامنة (Async/Await) ```typescript async function fetchUser(id: number): Promise<{ id: number; name: string }> { // محاكاة طلب API return { id, name: "أحمد" }; } async function main() { const user = await fetchUser(1); console.log(user.name); // أحمد } ``` ## Generics في الدوال Generics تسمح للدالة بالعمل مع أنواع مختلفة: ```typescript function identity<T>(value: T): T { return value; } console.log(identity<string>("أحمد")); // أحمد console.log(identity<number>(25)); // 25 console.log(identity<boolean>(true)); // true // TypeScript تستنتج النوع تلقائياً: console.log(identity("أحمد")); // أحمد ``` ## تمارين عملية ### تمرين 1: دالة الترحيب اكتب دالة تأخذ اسماً وترجع "مرحباً [الاسم]". **الحل:** ```typescript function greet(name: string): string { return `مرحباً ${name}`; } console.log(greet("أحمد")); // مرحباً أحمد ``` ### تمرين 2: دالة المجموع اكتب دالة تأخذ رقمين وترجع مجموعهما. **الحل:** ```typescript const add = (a: number, b: number): number => a + b; console.log(add(5, 3)); // 8 console.log(add(10, 20)); // 30 ``` ### تمرين 3: دالة الأكبر اكتب دالة تأخذ رقمين وترجع الأكبر. **الحل:** ```typescript function max(a: number, b: number): number { return a > b ? a : b; } console.log(max(5, 10)); // 10 console.log(max(20, 8)); // 20 ``` ### تمرين 4: دالة الزوجي اكتب دالة تتحقق إذا كان الرقم زوجياً. **الحل:** ```typescript const isEven = (num: number): boolean => num % 2 === 0; console.log(isEven(4)); // true console.log(isEven(7)); // false ``` ### تمرين 5: دالة المساحة اكتب دالة تحسب مساحة مستطيل. **الحل:** ```typescript function area(width: number, height: number): number { return width * height; } console.log(area(5, 10)); // 50 ``` ### تمرين 6: دالة المتوسط اكتب دالة تأخذ مصفوفة أرقام وترجع متوسطها. **الحل:** ```typescript function average(numbers: number[]): number { if (numbers.length === 0) return 0; const sum = numbers.reduce((acc, n) => acc + n, 0); return sum / numbers.length; } console.log(average([10, 20, 30, 40])); // 25 ``` ### تمرين 7: دالة Rest Parameters اكتب دالة تجمع أي عدد من الأرقام. **الحل:** ```typescript function sum(...numbers: number[]): number { return numbers.reduce((acc, n) => acc + n, 0); } console.log(sum(1, 2, 3)); // 6 console.log(sum(1, 2, 3, 4, 5)); // 15 ``` ### تمرين 8: دالة Overload اكتب دالة تستقبل `string` أو `string[]` وترجع ترحيباً مناسباً. **الحل:** ```typescript function greet(name: string): string; function greet(names: string[]): string; function greet(value: string | string[]): string { if (Array.isArray(value)) { return `مرحباً ${value.join(", ")}`; } return `مرحباً ${value}`; } console.log(greet("أحمد")); // مرحباً أحمد console.log(greet(["أحمد", "محمد"])); // مرحباً أحمد, محمد ``` ## حل المشاكل الشائعة ### 🔴 المشكلة 1: `Expected X arguments, but got Y` **السبب:** عدد المعاملات غير متطابق. ```typescript function add(a: number, b: number): number { return a + b; } add(5); // ❌ Expected 2 arguments, but got 1 ``` **الحل:** مرر العدد الصحيح من المعاملات، أو اجعلها اختيارية. ### 🔴 المشكلة 2: `Type 'X' is not assignable to type 'Y'` **السبب:** نوع المعامل أو القيمة المرجعة مختلف. ```typescript function add(a: number, b: number): number { return "5"; // ❌ يجب أن يكون number } ``` **الحل:** تأكد من تطابق الأنواع. ### 🔴 المشكلة 3: `A function whose declared type is neither 'void' nor 'any' must return a value` **السبب:** نسيت `return`. ```typescript function add(a: number, b: number): number { a + b; // ❌ لا return } ``` **الحل:** أضف `return`. ### 🔴 المشكلة 4: `Argument of type 'string' is not assignable to parameter of type 'number'` **السبب:** تمرير نوع خاطئ. ```typescript function greet(name: string) {} greet(25); // ❌ ``` **الحل:** مرر النوع الصحيح. ## جدول الأوامر الأساسية <table> <thead> <tr> <th>الأمر</th> <th>الوظيفة</th> </tr> </thead> <tbody> <tr> <td><code>function name(): type { }</code></td> <td>تعريف دالة</td> </tr> <tr> <td><code>const fn = (): type =&gt; { }</code></td> <td>دالة سهمية</td> </tr> <tr> <td><code>param?: type</code></td> <td>معامل اختياري</td> </tr> <tr> <td><code>param: type = default</code></td> <td>قيمة افتراضية</td> </tr> <tr> <td><code>...params: type[]</code></td> <td>معاملات متبقية</td> </tr> <tr> <td><code>: void</code></td> <td>لا قيمة مرجعة</td> </tr> <tr> <td><code>: never</code></td> <td>لا يحدث أبداً</td> </tr> <tr> <td><code>function f(): T</code></td> <td>Generics</td> </tr> </tbody> </table> ## قائمة تحقق نهائية <table> <thead> <tr> <th>المهمة</th> <th>الحالة</th> </tr> </thead> <tbody> <tr> <td>فهم تعريف الدوال واستدعاؤها</td> <td>⬜</td> </tr> <tr> <td>استخدام المعاملات والقيم المرجعة</td> <td>⬜</td> </tr> <tr> <td>المعاملات الاختيارية والافتراضية</td> <td>⬜</td> </tr> <tr> <td>Rest Parameters</td> <td>⬜</td> </tr> <tr> <td>Function Overloads</td> <td>⬜</td> </tr> <tr> <td>Callbacks</td> <td>⬜</td> </tr> <tr> <td>Generics</td> <td>⬜</td> </tr> <tr> <td>حل التمارين الثمانية</td> <td>⬜</td> </tr> </tbody> </table> ## ماذا بعد هذا المقال؟ الآن بعد أن أتقنت الدوال، أنت جاهز للمقال التالي: 1. **الفئات (Classes)** — البرمجة كائنية التوجه. 2. **الأدوية (Generics)** — تعمق في الأدوية. 3. **الأنواع المتقدمة** — Utility Types. ## الخلاصة في هذا المقال، تعلمت: - ✅ تعريف الدوال بأنواع. - ✅ أنواع المعاملات (اختيارية، افتراضية، متبقية). - ✅ أنواع القيم المرجعة. - ✅ Function Types و Callbacks. - ✅ Higher-Order Functions. - ✅ Function Overloads. - ✅ الدوال العودية. - ✅ Async/Await. - ✅ Generics في الدوال. **تذكر:** الدوال هي أدواتك الأساسية لتنظيم الكود. كلما أتقنتها، كلما أصبح كودك أنظف وأسهل صيانة. **هل أتقنت الدوال؟ شاركنا في التعليقات!**