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 => { }</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 في الدوال.
**تذكر:** الدوال هي أدواتك الأساسية لتنظيم الكود. كلما أتقنتها، كلما أصبح كودك أنظف وأسهل صيانة.
**هل أتقنت الدوال؟ شاركنا في التعليقات!**