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("أحمد", "ahmed@example.com"); // يطبع: تم إنشاء مستخدم جديد! ``` ## طريقة مختصرة (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, "ahmed@example.com"); 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). **تذكر:** الفئات هي أساس البرمجة كائنية التوجه. أتقنها جيداً، وستتمكن من بناء تطبيقات معقدة. **هل أتقنت الفئات؟ شاركنا في التعليقات!**