TypeScript
الفئات في TypeScript — دليل شامل Classes 2026
📅 2026-10-05⏱ 11 دقائق قراءة
في المقال السابق، تعلمت الدوال مع الأنواع. الآن سنتعمق في **الفئات (Classes)** — وهي أساس **البرمجة كائنية التوجه (OOP)** في TypeScript.
في هذا الدليل العملي، سنأخذك خطوة بخطوة لفهم الفئات، والوراثة، ومحددات الوصول، مع تمارين وحلول.
## ما هي الفئة (Class)؟
الفئة هي **قالب** لإنشاء كائنات (Objects). تحتوي على:
- **الخصائص (Properties):** البيانات.
- **الطرق (Methods):** الدوال.
- **Constructor:** دالة تُنفَّذ عند إنشاء الكائن.
**مثال بسيط:**
```typescript
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): string {
return `مرحباً، اسمي ${this.name} وعمري ${this.age}`;
}
}
const ahmed = new Person("أحمد", 25);
console.log(ahmed.greet()); // مرحباً، اسمي أحمد وعمري 25
```
**شرح:**
- **`class Person`:** تعريف فئة.
- **`name: string`:** خاصية.
- **`constructor`:** دالة تُنفَّذ عند `new Person(...)`.
- **`greet()`:** طريقة (method).
- **`new Person("أحمد", 25)`:** إنشاء كائن جديد.
## لماذا نحتاج الفئات؟
- **التنظيم:** تجميع البيانات والوظائف معاً.
- **إعادة الاستخدام:** الوراثة (Inheritance).
- **الأمان:** تحديد من يمكنه الوصول للبيانات.
- **الوضوح:** الكود يعكس كائنات العالم الحقيقي.
## تعريف فئة بسيطة
```typescript
class Car {
brand: string;
model: string;
year: number;
constructor(brand: string, model: string, year: number) {
this.brand = brand;
this.model = model;
this.year = year;
}
getInfo(): string {
return `${this.brand} ${this.model} (${this.year})`;
}
}
const car = new Car("تويوتا", "كامري", 2024);
console.log(car.getInfo()); // تويوتا كامري (2024)
```
## Constructor — البانية
الـ Constructor هي دالة خاصة تُنفَّذ عند إنشاء الكائن:
```typescript
class User {
name: string;
email: string;
constructor(name: string, email: string) {
this.name = name;
this.email = email;
console.log("تم إنشاء مستخدم جديد!");
}
}
const user = new User("أحمد", "[email protected]");
// يطبع: تم إنشاء مستخدم جديد!
```
## طريقة مختصرة (Parameter Properties)
يمكنك تعريف الخصائص مباشرة في الـ Constructor:
```typescript
class Person {
constructor(
public name: string,
public age: number,
private email: string
) {}
getInfo(): string {
return `${this.name} (${this.age})`;
}
}
const person = new Person("أحمد", 25, "[email protected]");
console.log(person.name); // أحمد
console.log(person.age); // 25
// console.log(person.email); // ❌ خطأ: private
```
**الفائدة:** كود أقل، ووضوح أكثر.
## محددات الوصول (Access Modifiers)
TypeScript توفر **3 محددات وصول**:
<table>
<thead>
<tr>
<th>المحدد</th>
<th>الوصول</th>
<th>الاستخدام</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>public</code></td>
<td>من أي مكان (افتراضي)</td>
<td>للخصائص العامة</td>
</tr>
<tr>
<td><code>private</code></td>
<td>داخل الفئة فقط</td>
<td>للبيانات الحساسة</td>
</tr>
<tr>
<td><code>protected</code></td>
<td>داخل الفئة والفئات الوريثة</td>
<td>للمشاركة مع الفئات الفرعية</td>
</tr>
</tbody>
</table>
### 1. `public`
```typescript
class Person {
public name: string;
constructor(name: string) {
this.name = name;
}
}
const person = new Person("أحمد");
console.log(person.name); // ✅ أحمد
```
### 2. `private`
```typescript
class BankAccount {
private balance: number;
constructor(initialBalance: number) {
this.balance = initialBalance;
}
deposit(amount: number): void {
this.balance += amount;
}
getBalance(): number {
return this.balance;
}
}
const account = new BankAccount(1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
// console.log(account.balance); // ❌ خطأ: private
```
### 3. `protected`
```typescript
class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
bark(): void {
console.log(`${this.name} يقول: هاو هاو!`); // ✅ يمكن الوصول
}
}
const dog = new Dog("روكي");
dog.bark(); // روكي يقول: هاو هاو!
```
## Readonly Properties
```typescript
class User {
readonly id: number;
name: string;
constructor(id: number, name: string) {
this.id = id;
this.name = name;
}
}
const user = new User(1, "أحمد");
user.name = "محمد"; // ✅
// user.id = 2; // ❌ خطأ: readonly
```
## الوراثة (Inheritance)
الوراثة تسمح لفئة بأخذ خصائص وطرق فئة أخرى:
```typescript
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound(): void {
console.log("صوت غير معروف");
}
}
class Dog extends Animal {
makeSound(): void {
console.log(`${this.name} يقول: هاو هاو!`);
}
}
class Cat extends Animal {
makeSound(): void {
console.log(`${this.name} يقول: مياو!`);
}
}
const dog = new Dog("روكي");
dog.makeSound(); // روكي يقول: هاو هاو!
const cat = new Cat("مشمش");
cat.makeSound(); // مشمش يقول: مياو!
```
**شرح:**
- **`extends Animal`:** فئة `Dog` ترث من `Animal`.
- **`makeSound()`:** إعادة تعريف (override) للطريقة.
## `super` — استدعاء الفئة الأم
```typescript
class Animal {
constructor(public name: string) {}
makeSound(): void {
console.log("صوت غير معروف");
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name); // استدعاء constructor الفئة الأم
}
makeSound(): void {
super.makeSound(); // استدعاء طريقة الفئة الأم
console.log("هاو هاو!");
}
}
const dog = new Dog("روكي", "جولدن");
dog.makeSound();
// صوت غير معروف
// هاو هاو!
```
## الفئات المجردة (Abstract Classes)
الفئة المجردة **لا يمكن إنشاء كائن منها مباشرة**، بل يجب أن تُورَّث:
```typescript
abstract class Shape {
abstract area(): number; // يجب على الفئة الوريثة تنفيذها
describe(): string {
return `المساحة: ${this.area()}`;
}
}
class Circle extends Shape {
constructor(private radius: number) {
super();
}
area(): number {
return Math.PI * this.radius ** 2;
}
}
class Rectangle extends Shape {
constructor(private width: number, private height: number) {
super();
}
area(): number {
return this.width * this.height;
}
}
const circle = new Circle(5);
console.log(circle.describe()); // المساحة: 78.5398...
const rect = new Rectangle(4, 6);
console.log(rect.describe()); // المساحة: 24
// const shape = new Shape(); // ❌ خطأ: abstract
```
## Getters و Setters
```typescript
class User {
private _name: string = "";
get name(): string {
return this._name;
}
set name(value: string) {
if (value.length < 2) {
throw new Error("الاسم قصير جداً");
}
this._name = value;
}
}
const user = new User();
user.name = "أحمد";
console.log(user.name); // أحمد
// user.name = "أ"; // ❌ خطأ: الاسم قصير جداً
```
## Static Properties و Methods
Static تعني أن الخاصية أو الطريقة تنتمي للفئة نفسها، وليس للكائنات:
```typescript
class MathUtils {
static PI: number = 3.14159;
static add(a: number, b: number): number {
return a + b;
}
static multiply(a: number, b: number): number {
return a * b;
}
}
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.add(5, 3)); // 8
console.log(MathUtils.multiply(4, 5)); // 20
// لا تحتاج إلى new MathUtils()
```
## تنفيذ الواجهات (implements)
الفئات يمكنها تنفيذ الواجهات:
```typescript
interface Animal {
name: string;
makeSound(): void;
}
class Dog implements Animal {
constructor(public name: string) {}
makeSound(): void {
console.log(`${this.name} يقول: هاو هاو!`);
}
}
const dog = new Dog("روكي");
dog.makeSound();
```
## مثال عملي: نظام موظفين
```typescript
abstract class Employee {
constructor(
public id: number,
public name: string,
protected salary: number
) {}
abstract calculateBonus(): number;
getDetails(): string {
return `الموظف: ${this.name} (ID: ${this.id})`;
}
getSalary(): number {
return this.salary;
}
}
class Manager extends Employee {
constructor(id: number, name: string, salary: number, private teamSize: number) {
super(id, name, salary);
}
calculateBonus(): number {
return this.salary * 0.2; // 20% مدير
}
}
class Developer extends Employee {
constructor(id: number, name: string, salary: number, private language: string) {
super(id, name, salary);
}
calculateBonus(): number {
return this.salary * 0.1; // 10% مطور
}
getLanguage(): string {
return this.language;
}
}
const manager = new Manager(1, "أحمد", 10000, 5);
console.log(manager.getDetails()); // الموظف: أحمد (ID: 1)
console.log(manager.calculateBonus()); // 2000
const developer = new Developer(2, "محمد", 8000, "TypeScript");
console.log(developer.getDetails()); // الموظف: محمد (ID: 2)
console.log(developer.calculateBonus()); // 800
console.log(developer.getLanguage()); // TypeScript
```
## تمارين عملية
### تمرين 1: فئة Person
أنشئ فئة `Person` لها `name` و `age` وطريقة `greet()`.
**الحل:**
```typescript
class Person {
constructor(public name: string, public age: number) {}
greet(): string {
return `مرحباً، اسمي ${this.name} وعمري ${this.age}`;
}
}
const person = new Person("أحمد", 25);
console.log(person.greet());
```
### تمرين 2: فئة Rectangle
أنشئ فئة `Rectangle` لها `width` و `height`، وطريقة `area()`.
**الحل:**
```typescript
class Rectangle {
constructor(public width: number, public height: number) {}
area(): number {
return this.width * this.height;
}
}
const rect = new Rectangle(5, 10);
console.log(rect.area()); // 50
```
### تمرين 3: الوراثة
أنشئ فئة `Animal`، ثم `Dog` و `Cat` ترث منها.
**الحل:**
```typescript
class Animal {
constructor(public name: string) {}
makeSound(): void {
console.log("صوت غير معروف");
}
}
class Dog extends Animal {
makeSound(): void {
console.log(`${this.name}: هاو هاو!`);
}
}
class Cat extends Animal {
makeSound(): void {
console.log(`${this.name}: مياو!`);
}
}
new Dog("روكي").makeSound(); // روكي: هاو هاو!
new Cat("مشمش").makeSound(); // مشمش: مياو!
```
### تمرين 4: Private
أنشئ فئة `BankAccount` لها `balance` خاص.
**الحل:**
```typescript
class BankAccount {
private balance: number = 0;
deposit(amount: number): void {
if (amount > 0) this.balance += amount;
}
withdraw(amount: number): void {
if (amount > 0 && amount <= this.balance) {
this.balance -= amount;
}
}
getBalance(): number {
return this.balance;
}
}
const account = new BankAccount();
account.deposit(1000);
account.withdraw(300);
console.log(account.getBalance()); // 700
```
### تمرين 5: Abstract Class
أنشئ فئة مجردة `Shape` لها `area()`.
**الحل:**
```typescript
abstract class Shape {
abstract area(): number;
describe(): string {
return `المساحة: ${this.area()}`;
}
}
class Circle extends Shape {
constructor(private radius: number) {
super();
}
area(): number {
return Math.PI * this.radius ** 2;
}
}
console.log(new Circle(5).describe());
```
### تمرين 6: Static
أنشئ فئة `MathUtils` لها دوال static.
**الحل:**
```typescript
class MathUtils {
static add(a: number, b: number): number {
return a + b;
}
static subtract(a: number, b: number): number {
return a - b;
}
}
console.log(MathUtils.add(5, 3)); // 8
console.log(MathUtils.subtract(5, 3)); // 2
```
### تمرين 7: Getters و Setters
أنشئ فئة `Temperature` لها `celsius` مع getter/setter.
**الحل:**
```typescript
class Temperature {
private _celsius: number = 0;
get celsius(): number {
return this._celsius;
}
set celsius(value: number) {
if (value < -273.15) {
throw new Error("أقل من الصفر المطلق!");
}
this._celsius = value;
}
get fahrenheit(): number {
return this._celsius * 9 / 5 + 32;
}
}
const temp = new Temperature();
temp.celsius = 25;
console.log(temp.celsius); // 25
console.log(temp.fahrenheit); // 77
```
### تمرين 8: نظام حيوانات
أنشئ نظاماً كاملاً بفئات حيوانات.
**الحل:**
```typescript
abstract class Animal {
constructor(public name: string) {}
abstract makeSound(): string;
}
class Dog extends Animal {
makeSound(): string {
return `${this.name}: هاو هاو!`;
}
}
class Cat extends Animal {
makeSound(): string {
return `${this.name}: مياو!`;
}
}
class Cow extends Animal {
makeSound(): string {
return `${this.name}: مووو!`;
}
}
const animals: Animal[] = [
new Dog("روكي"),
new Cat("مشمش"),
new Cow("بقرودة"),
];
animals.forEach((animal) => console.log(animal.makeSound()));
```
## حل المشاكل الشائعة
### 🔴 المشكلة 1: `Property 'X' has no initializer`
**السبب:** خاصية لم تُهيأ في الـ Constructor.
```typescript
class Person {
name: string; // ❌ خطأ
}
```
**الحل:**
```typescript
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
}
// أو:
class Person {
name: string = "";
}
// أو:
class Person {
constructor(public name: string) {}
}
```
### 🔴 المشكلة 2: `Cannot access 'X' before initialization`
**السبب:** استخدام `this` قبل `super()`.
```typescript
class Dog extends Animal {
constructor(name: string) {
this.name = name; // ❌
super();
}
}
```
**الحل:** استدعِ `super()` أولاً:
```typescript
class Dog extends Animal {
constructor(name: string) {
super();
this.name = name; // ✅
}
}
```
### 🔴 المشكلة 3: `Cannot create an instance of an abstract class`
**السبب:** محاولة إنشاء كائن من فئة مجردة.
```typescript
abstract class Shape {}
const shape = new Shape(); // ❌
```
**الحل:** أنشئ فئة فرعية ترث منها.
### 🔴 المشكلة 4: `Property 'X' is private`
**السبب:** الوصول لخاصية private من خارج الفئة.
```typescript
class User {
private password: string = "123";
}
const user = new User();
console.log(user.password); // ❌
```
**الحل:** اجعلها `public` أو أضف getter.
## جدول الأوامر الأساسية
<table>
<thead>
<tr>
<th>الأمر</th>
<th>الوظيفة</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>class X { }</code></td>
<td>تعريف فئة</td>
</tr>
<tr>
<td><code>constructor() { }</code></td>
<td>الـ Constructor</td>
</tr>
<tr>
<td><code>new X()</code></td>
<td>إنشاء كائن</td>
</tr>
<tr>
<td><code>class X extends Y</code></td>
<td>وراثة</td>
</tr>
<tr>
<td><code>super()</code></td>
<td>استدعاء الفئة الأم</td>
</tr>
<tr>
<td><code>public, private, protected</code></td>
<td>محددات الوصول</td>
</tr>
<tr>
<td><code>readonly</code></td>
<td>للقراءة فقط</td>
</tr>
<tr>
<td><code>abstract</code></td>
<td>فئة مجردة</td>
</tr>
<tr>
<td><code>static</code></td>
<td>ينتمي للفئة</td>
</tr>
<tr>
<td><code>get / set</code></td>
<td>Getters/Setters</td>
</tr>
<tr>
<td><code>implements</code></td>
<td>تنفيذ واجهة</td>
</tr>
</tbody>
</table>
## قائمة تحقق نهائية
<table>
<thead>
<tr>
<th>المهمة</th>
<th>الحالة</th>
</tr>
</thead>
<tbody>
<tr>
<td>فهم تعريف الفئات والـ Constructor</td>
<td>⬜</td>
</tr>
<tr>
<td>محددات الوصول (public, private, protected)</td>
<td>⬜</td>
</tr>
<tr>
<td>الوراثة (extends) و super</td>
<td>⬜</td>
</tr>
<tr>
<td>الفئات المجردة (abstract)</td>
<td>⬜</td>
</tr>
<tr>
<td>Static Properties/Methods</td>
<td>⬜</td>
</tr>
<tr>
<td>Getters و Setters</td>
<td>⬜</td>
</tr>
<tr>
<td>تنفيذ الواجهات (implements)</td>
<td>⬜</td>
</tr>
<tr>
<td>حل التمارين الثمانية</td>
<td>⬜</td>
</tr>
</tbody>
</table>
## ماذا بعد هذا المقال؟
الآن بعد أن أتقنت الفئات، أنت جاهز للمقال التالي:
1. **الأدوية (Generics)** — الأنواع العامة.
2. **الأنواع المتقدمة** — Utility Types.
3. **مشروع React** — تطبيق عملي.
## الخلاصة
في هذا المقال، تعلمت:
- ✅ تعريف الفئات والـ Constructor.
- ✅ محددات الوصول (public, private, protected).
- ✅ Readonly Properties.
- ✅ الوراثة (extends) و super.
- ✅ الفئات المجردة (abstract).
- ✅ Getters و Setters.
- ✅ Static Properties/Methods.
- ✅ تنفيذ الواجهات (implements).
**تذكر:** الفئات هي أساس البرمجة كائنية التوجه. أتقنها جيداً، وستتمكن من بناء تطبيقات معقدة.
**هل أتقنت الفئات؟ شاركنا في التعليقات!**