TypeScript
الواجهات في TypeScript — دليل شامل Interfaces 2026
📅 2026-10-03⏱ 9 دقائق قراءة
في المقال السابق، تعلمت الأنواع الأساسية في TypeScript. الآن سنتعمق في **الواجهات (Interfaces)** — وهي إحدى أقوى ميزات TypeScript لتعريف **هياكل البيانات**.
في هذا الدليل العملي، سنأخذك خطوة بخطوة لفهم الواجهات، والفرق بينها وبين `type`، وكيفية استخدامها في مشاريعك، مع تمارين وحلول.
## ما هي الواجهة (Interface)؟
الواجهة هي **عقد (Contract)** يحدد **شكل** الكائن — ما الخصائص التي يجب أن يحتويها، وما أنواعها.
**تشبيه بسيط:** تخيل أن الواجهة هي "قالب" أو "مخطط" لبناء منزل. أي منزل يُبنى من هذا القالب يجب أن يحتوي على: غرفة نوم، مطبخ، حمام.
**مثال:**
```typescript
interface User {
name: string;
age: number;
email: string;
}
const user: User = {
name: "أحمد",
age: 25,
email: "[email protected]",
};
```
**شرح:**
- **`interface User`:** تعريف واجهة باسم `User`.
- **`{ name: string; ... }`:** الخصائص المطلوبة.
- **`: User`:** المتغير `user` يجب أن يطابق واجهة `User`.
**⚠️ مهم:** إذا نسيت خاصية أو كتبتها بنوع خاطئ، TypeScript ستعطي خطأ:
```typescript
const user: User = {
name: "أحمد",
age: "25", // ❌ خطأ: يجب أن يكون number
// ❌ خطأ: email مفقود
};
```
## لماذا نحتاج الواجهات؟
- **الوضوح:** الكود يوثق نفسه.
- **الأمان:** تكتشف الأخطاء قبل التشغيل.
- **إعادة الاستخدام:** عرّف الواجهة مرة، استخدمها في أماكن كثيرة.
- **الأدوات:** إكمال تلقائي (IntelliSense) أفضل.
- **التعاون:** الفريق يفهم بنية البيانات.
## الخصائص الاختيارية (Optional Properties)
استخدم `?` لجعل خاصية اختيارية:
```typescript
interface User {
name: string;
age: number;
email?: string; // اختياري
}
const user1: User = {
name: "أحمد",
age: 25,
}; // ✅ صحيح
const user2: User = {
name: "محمد",
age: 30,
email: "[email protected]",
}; // ✅ صحيح
```
## خصائص القراءة فقط (Readonly)
استخدم `readonly` لمنع التعديل بعد الإنشاء:
```typescript
interface Config {
readonly apiKey: string;
readonly baseUrl: string;
timeout: number; // قابل للتعديل
}
const config: Config = {
apiKey: "abc123",
baseUrl: "https://api.example.com",
timeout: 5000,
};
config.timeout = 10000; // ✅ مسموح
// config.apiKey = "new-key"; // ❌ خطأ
```
## طرق (Methods) في الواجهات
يمكنك تعريف دوال داخل الواجهة:
```typescript
interface Calculator {
add(a: number, b: number): number;
subtract(a: number, b: number): number;
}
const calc: Calculator = {
add(a, b) {
return a + b;
},
subtract(a, b) {
return a - b;
},
};
console.log(calc.add(5, 3)); // 8
console.log(calc.subtract(5, 3)); // 2
```
## الفهارس (Index Signatures)
إذا كنت لا تعرف أسماء الخصائص مسبقاً:
```typescript
interface StringMap {
[key: string]: string;
}
const colors: StringMap = {
red: "#FF0000",
green: "#00FF00",
blue: "#0000FF",
};
console.log(colors.red); // #FF0000
console.log(colors["green"]); // #00FF00
```
**مثال عملي:** قاموس (Dictionary):
```typescript
interface Dictionary {
[key: string]: number;
}
const ages: Dictionary = {
ahmed: 25,
mohamed: 30,
ali: 22,
};
console.log(ages.ahmed); // 25
```
## توسيع الواجهات (Interface Extension)
يمكنك بناء واجهة على واجهة أخرى باستخدام `extends`:
```typescript
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
company: string;
salary: number;
}
const emp: Employee = {
name: "أحمد",
age: 25,
company: "Google",
salary: 50000,
};
```
**توسيع متعدد:**
```typescript
interface A {
a: string;
}
interface B {
b: string;
}
interface C extends A, B {
c: string;
}
const obj: C = {
a: "a",
b: "b",
c: "c",
};
```
## تنفيذ الواجهات (implements)
الفئات (Classes) يمكنها تنفيذ الواجهات:
```typescript
interface Animal {
name: string;
makeSound(): void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound(): void {
console.log(`${this.name} يقول: هاو هاو!`);
}
}
const dog = new Dog("روكي");
dog.makeSound(); // روكي يقول: هاو هاو!
```
## الفرق بين `interface` و `type`
هذا سؤال شائع جداً. دعنا نوضح:
<table>
<thead>
<tr>
<th>المعيار</th>
<th>interface</th>
<th>type</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>تعريف الكائنات</strong></td>
<td>✅ ممتاز</td>
<td>✅ ممتاز</td>
</tr>
<tr>
<td><strong>Union Types</strong></td>
<td>❌ لا يدعم</td>
<td>✅ يدعم</td>
</tr>
<tr>
<td><strong>Intersection</strong></td>
<td>✅ عبر extends</td>
<td>✅ عبر &</td>
</tr>
<tr>
<td><strong>إعادة التعريف (Declaration Merging)</strong></td>
<td>✅ يدعم</td>
<td>❌ لا يدعم</td>
</tr>
<tr>
<td><strong>implements في Classes</strong></td>
<td>✅ يدعم</td>
<td>✅ يدعم</td>
</tr>
<tr>
<td><strong>Tuple</strong></td>
<td>❌ لا يدعم</td>
<td>✅ يدعم</td>
</tr>
</tbody>
</table>
### متى تستخدم `interface`؟
- لتعريف **شكل الكائنات** (Objects).
- للفئات (Classes) التي تنفذ الواجهة.
- عندما تحتاج إلى **إعادة تعريف** (Declaration Merging).
### متى تستخدم `type`؟
- لـ **Union Types** (`string | number`).
- لـ **Tuple** (`[string, number]`).
- للأنواع البدائية (`type ID = string | number`).
- للأنواع المعقدة (Conditional, Mapped, ...).
### مثال مقارن:
```typescript
// interface
interface User {
name: string;
age: number;
}
// type
type User = {
name: string;
age: number;
};
```
**كلاهما يعمل بنفس الطريقة** لتحديد شكل الكائن.
**لكن:**
```typescript
// type يدعم Union
type Status = "pending" | "approved" | "rejected";
// interface لا يدعم Union
// interface Status = "pending" | "approved"; // ❌ خطأ
```
### إعادة التعريف (Declaration Merging):
```typescript
// interface: يمكن إعادة تعريفها
interface User {
name: string;
}
interface User {
age: number;
}
// النتيجة: User له name و age
const user: User = {
name: "أحمد",
age: 25,
};
// type: لا يمكن إعادة تعريفها
type Person = { name: string };
// type Person = { age: number }; // ❌ خطأ
```
## الواجهات للدوال (Call Signatures)
يمكنك تعريف واجهة تمثل دالة:
```typescript
interface GreetFunction {
(name: string): string;
}
const greet: GreetFunction = (name) => `مرحباً ${name}`;
console.log(greet("أحمد")); // مرحباً أحمد
```
## الواجهات للفئات (Construct Signatures)
```typescript
interface PersonConstructor {
new (name: string, age: number): Person;
}
interface Person {
name: string;
age: number;
}
class PersonImpl implements Person {
constructor(public name: string, public age: number) {}
}
const PersonClass: PersonConstructor = PersonImpl;
const person = new PersonClass("أحمد", 25);
```
## تمارين عملية
### تمرين 1: واجهة مستخدم
عرّف واجهة `User` تحتوي على:
- id (number)
- name (string)
- email (string)
- isActive (boolean)
**الحل:**
```typescript
interface User {
id: number;
name: string;
email: string;
isActive: boolean;
}
const user: User = {
id: 1,
name: "أحمد",
email: "[email protected]",
isActive: true,
};
```
### تمرين 2: خصائص اختيارية
عرّف واجهة `Product` تحتوي على:
- name (string)
- price (number)
- description (string, اختياري)
- discount (number, اختياري)
**الحل:**
```typescript
interface Product {
name: string;
price: number;
description?: string;
discount?: number;
}
const product1: Product = {
name: "لابتوب",
price: 5000,
};
const product2: Product = {
name: "هاتف",
price: 2000,
description: "هاتف ذكي",
discount: 10,
};
```
### تمرين 3: توسيع الواجهات
عرّف `Person`، ثم `Student` يرث منها.
**الحل:**
```typescript
interface Person {
name: string;
age: number;
}
interface Student extends Person {
studentId: string;
major: string;
}
const student: Student = {
name: "أحمد",
age: 20,
studentId: "S12345",
major: "علوم حاسب",
};
```
### تمرين 4: دالة في واجهة
عرّف واجهة `Shape` لها دالة `area()`.
**الحل:**
```typescript
interface Shape {
area(): number;
}
const circle: Shape = {
area() {
return Math.PI * 5 * 5;
},
};
console.log(circle.area()); // 78.5398...
```
### تمرين 5: قاموس
عرّف `Dictionary` يخزن `string -> number`.
**الحل:**
```typescript
interface Dictionary {
[key: string]: number;
}
const scores: Dictionary = {
ahmed: 95,
mohamed: 88,
ali: 92,
};
console.log(scores.ahmed); // 95
```
### تمرين 6: implements
أنشئ واجهة `Vehicle` وفئة `Car` تنفذها.
**الحل:**
```typescript
interface Vehicle {
brand: string;
speed: number;
accelerate(): void;
}
class Car implements Vehicle {
brand: string;
speed: number;
constructor(brand: string, speed: number) {
this.brand = brand;
this.speed = speed;
}
accelerate(): void {
this.speed += 10;
console.log(`${this.brand} تسارع إلى ${this.speed} كم/س`);
}
}
const car = new Car("تويوتا", 100);
car.accelerate(); // تويوتا تسارع إلى 110 كم/س
```
### تمرين 7: واجهة API Response
عرّف واجهة تمثل استجابة API.
**الحل:**
```typescript
interface ApiResponse<T> {
success: boolean;
data: T;
message?: string;
}
interface User {
id: number;
name: string;
}
const response: ApiResponse<User> = {
success: true,
data: { id: 1, name: "أحمد" },
message: "تم بنجاح",
};
```
**⚠️ ملاحظة:** هذا مثال متقدم قليلاً (Generics). سنتعلمه في مقال لاحق.
### تمرين 8: الفرق بين interface و type
عرّف نوع `Status` باستخدام `type`، ونوع `User` باستخدام `interface`.
**الحل:**
```typescript
type Status = "active" | "inactive" | "pending";
interface User {
id: number;
name: string;
status: Status;
}
const user: User = {
id: 1,
name: "أحمد",
status: "active",
};
```
## حل المشاكل الشائعة
### 🔴 المشكلة 1: `Property 'X' is missing`
**السبب:** نسيت خاصية مطلوبة.
```typescript
interface User {
name: string;
age: number;
}
const user: User = {
name: "أحمد",
// ❌ age مفقود
};
```
**الحل:** أضف الخاصية المفقودة، أو اجعلها اختيارية `?`.
### 🔴 المشكلة 2: `Type 'X' is not assignable to type 'Y'`
**السبب:** نوع خاصية مختلف.
```typescript
interface User {
age: number;
}
const user: User = {
age: "25", // ❌ يجب أن يكون number
};
```
**الحل:** استخدم النوع الصحيح.
### 🔴 المشكلة 3: `Cannot assign to 'X' because it is a read-only property`
**السبب:** حاولت تعديل خاصية `readonly`.
**الحل:** احذف `readonly` إذا كنت تريد التعديل، أو لا تعدّل.
### 🔴 المشكلة 4: `Interface 'X' incorrectly extends interface 'Y'`
**السبب:** توسيع واجهة بنوع غير متوافق.
**الحل:** تأكد من توافق الأنواع في الواجهة الفرعية.
## جدول الأوامر الأساسية
<table>
<thead>
<tr>
<th>الأمر</th>
<th>الوظيفة</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>interface X { }</code></td>
<td>تعريف واجهة</td>
</tr>
<tr>
<td><code>property?: type</code></td>
<td>خاصية اختيارية</td>
</tr>
<tr>
<td><code>readonly property</code></td>
<td>خاصية للقراءة فقط</td>
</tr>
<tr>
<td><code>interface X extends Y</code></td>
<td>توسيع واجهة</td>
</tr>
<tr>
<td><code>class X implements Y</code></td>
<td>تنفيذ واجهة</td>
</tr>
<tr>
<td><code>[key: string]: type</code></td>
<td>فهرس ديناميكي</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>استخدام readonly</td>
<td>⬜</td>
</tr>
<tr>
<td>تعريف دوال في الواجهات</td>
<td>⬜</td>
</tr>
<tr>
<td>توسيع الواجهات (extends)</td>
<td>⬜</td>
</tr>
<tr>
<td>تنفيذ الواجهات (implements)</td>
<td>⬜</td>
</tr>
<tr>
<td>فهم الفرق بين interface و type</td>
<td>⬜</td>
</tr>
<tr>
<td>حل التمارين الثمانية</td>
<td>⬜</td>
</tr>
</tbody>
</table>
## ماذا بعد هذا المقال؟
الآن بعد أن أتقنت الواجهات، أنت جاهز للمقال التالي:
1. **الدوال مع الأنواع** — تعمق في أنواع الدوال.
2. **الفئات (Classes)** — البرمجة كائنية التوجه.
3. **الأدوية (Generics)** — الأنواع العامة.
## الخلاصة
في هذا المقال، تعلمت:
- ✅ ما هي الواجهات ولماذا نحتاجها.
- ✅ تعريف الواجهات والخصائص الاختيارية.
- ✅ readonly و Index Signatures.
- ✅ الطرق (Methods) في الواجهات.
- ✅ توسيع الواجهات (extends).
- ✅ تنفيذ الواجهات (implements).
- ✅ الفرق بين interface و type.
**تذكر:** الواجهات هي أساس المشاريع الكبيرة في TypeScript. أتقنها جيداً.
**هل أتقنت الواجهات؟ شاركنا في التعليقات!**