TypeScript: فئة TypeScript (class)

آخر تحديث: 2026-08-26

تُعد «الفئات» إحدى ميزات بناء الجملة الموجهة للكائنات التي أُضيفت في لغة جافا سكريبت ES6. وتستند لغة تايب سكريبت إلى هذه الميزة من خلال إضافة تعليقات الأنواع والتحكم في الوصول — مما يضمن أن خصائص الفئات وأساليبها تخضع لقيود الأنواع.

1. القواعد الأساسية لبناء الفئات

(1) إعلانات المتغيرات والمنشئات

يتطلب TypeScript الإعلان عن خصائص الفئة قبل استخدامها — على عكس JavaScript:

TYPESCRIPT
class User {
  // Property Declaration(TypeScript Requirements)
  name: string;
  age: number;

  // Constructor
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  // Methods
  greet(): string {
    return `Hello,I am${this.name},This year${this.age} years old`;
  }
}

let user = new User("Charlie", 20);
console.log(user.greet());  // "Hello,I amCharlie,This year20 years old"

(2) طرق متعددة لتهيئة الخصائص

TYPESCRIPT
class Config {
  // Method 1:Initialize directly upon declaration
  host: string = "localhost";
  port: number = 3000;

  // Method 2:Initialization in the Constructor
  env: string;

  constructor(env: string) {
    this.env = env;
  }

  // Method 3:Assert that it is not empty(!)——You promise to assign a value later.
  data!: string;
}

let cfg = new Config("development");
cfg.data = "some data";  // Create First, Then Assign
🔥 خطأ شائع: إذا لم يتم تهيئة خاصية ما أو تعيين قيمة لها في منشئ الكائن، فسوف يُصدر TypeScript خطأً بعنوان «الخاصية لم يتم تهيئتها» (في الوضع الصارم). يمكنك التغلب على هذه المشكلة باستخدام التأكيد !، ولكن تأكد من تعيين قيمة لهذه الخاصية فعليًّا.



2. مُعدِّلات الوصول

تتحكم مُعدِّلات الوصول الثلاثة في TypeScript في مدى ظهور الخصائص والطرق:

المُعدِّل داخل الفئة الفئة الفرعية خارج الفئة
public
protected
private

(1) عام (الافتراضي)

TYPESCRIPT
class Person {
  public name: string;   // public This is the default value.,Optional
  public age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

let p = new Person("Charlie", 20);
console.log(p.name);  // ✅ Accessible from outside the class
p.name = "Diana";      // ✅ Can be modified from outside the class

(2) خاص

TYPESCRIPT
class BankAccount {
  private balance: number;

  constructor(initialBalance: number) {
    this.balance = initialBalance;
  }

  public deposit(amount: number): void {
    if (amount > 0) this.balance += amount;
  }

  public withdraw(amount: number): boolean {
    if (amount > 0 && amount <= this.balance) {
      this.balance -= amount;
      return true;
    }
    return false;
  }

  public getBalance(): number {
    return this.balance;
  }
}

let account = new BankAccount(1000);
account.deposit(500);
account.withdraw(200);
console.log(account.getBalance());  // 1300
// account.balance;                  // ❌ private The property is not accessible from outside
// account.balance = 99999;          // ❌ private Properties cannot be modified externally

(3) محمي

TYPESCRIPT
class Animal {
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  protected makeSound(sound: string): void {
    console.log(`${this.name}:${sound}`);
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }

  public bark(): void {
    this.makeSound("Woof!");  // ✅ Subclasses can access protected Methods
    // console.log(this.name);  // ✅ Subclasses can access protected Properties
  }
}

let dog = new Dog("Wangcai");
dog.bark();           // "Wangcai:Woof!"
// dog.name;           // ❌ protected The property is not accessible from outside
// dog.makeSound("Howl"); // ❌ protected This method cannot be called from outside the class.

(4) الاختصار في معلمات المنشئ

يوفر TypeScript خصائص المعلمات — فمن خلال إضافة مُعدِّلات قبل معلمات مُنشئ الدالة، يقوم تلقائيًّا بإعلان الخصائص وتهيئتها:

TYPESCRIPT
// Complete Syntax
class User1 {
  public name: string;
  private age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

// Abbreviation——The effect is exactly the same
class User2 {
  constructor(
    public name: string,
    private age: number
  ) {}
}

let u = new User2("Charlie", 20);
console.log(u.name);    // ✅ public
// console.log(u.age);  // ❌ private
💡 نصيحة: تجعل خصائص المعلمات الكود أكثر إيجازًا، لكن قابلية القراءة تنخفض عندما يكون عدد الخصائص كبيرًا جدًّا. في حالة وجود ثلاث خصائص أو أقل، استخدم الصيغة المختصرة؛ أما إذا كان العدد أكثر من ثلاث، فقم بإعلانها صراحةً.



3. المُعدِّل «readonly»

readonly لا يمكن تعيين قيم للخصائص التي تحتوي على مُعدِّلات إلا عند الإعلان عنها أو في مُنشئ الكائن:

TYPESCRIPT
class Circle {
  readonly radius: number;

  constructor(radius: number) {
    this.radius = radius;  // ✅ You can assign values in the constructor
  }

  get area(): number {
    return Math.PI * this.radius ** 2;
  }
}

let circle = new Circle(5);
console.log(circle.area);     // 78.54
// circle.radius = 10;        // ❌ readonly Properties cannot be modified

(1) خصائص "للقراءة فقط" + خصائص المعلمات

TYPESCRIPT
class Config {
  constructor(
    readonly host: string,
    readonly port: number
  ) {}
}

let cfg = new Config("localhost", 3000);
console.log(`${cfg.host}:${cfg.port}`);  // "localhost:3000"
// cfg.host = "other";  // ❌ readonly


4. أدوات الوصول (أدوات الاسترجاع / أدوات التعيين)

تتيح لك أدوات الوصول تنفيذ منطق مخصص عند قراءة الخصائص أو كتابتها:

(1) قواعد النحو الأساسية

TYPESCRIPT
class Employee {
  private _salary: number = 0;

  // getter——Execute on read
  get salary(): number {
    return this._salary;
  }

  // setter——Perform validation during assignment
  set salary(value: number) {
    if (value < 0) {
      throw new Error("Salaries cannot be negative.");
    }
    this._salary = value;
  }
}

let emp = new Employee();
emp.salary = 8000;       // Call setter
console.log(emp.salary);  // Call getter → 8000
// emp.salary = -100;     // ❌ Throw an error

(2) الخصائص المخصصة للقراءة فقط (التي تحتوي على دالة استرجاع دون دالة تعيين)

TYPESCRIPT
class User {
  constructor(
    private firstName: string,
    private lastName: string
  ) {}

  get fullName(): string {
    return `${this.firstName} ${this.lastName}`;
  }
  // None setter → fullName It is read-only.
}

let user = new User("San", "Zhang");
console.log(user.fullName);  // "San Zhang"
// user.fullName = "Si Li";  // ❌ None setter

▶ مثال: محول درجات الحرارة

TYPESCRIPT
class Temperature {
  private _celsius: number = 0;

  constructor(celsius: number) {
    this._celsius = celsius;
  }

  get celsius(): number {
    return this._celsius;
  }

  set celsius(value: number) {
    if (value < -273.15) {
      throw new Error("The temperature must not fall below absolute zero.(-273.15°C)");
    }
    this._celsius = value;
  }

  get fahrenheit(): number {
    return this._celsius * 9 / 5 + 32;
  }

  set fahrenheit(value: number) {
    this.celsius = (value - 32) * 5 / 9;  // Reuse celsius Verification of
  }
}

let temp = new Temperature(100);
console.log(`${temp.celsius}°C = ${temp.fahrenheit}°F`);  // "100°C = 212°F"

temp.fahrenheit = 32;
console.log(`${temp.celsius}°C = ${temp.fahrenheit}°F`);  // "0°C = 32°F"
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
100°C = 212°F
0°C = 32°F


5. العناصر الثابتة

static الخصائص والطرق المعدلة تنتمي إلى الفئة نفسها، وليس إلى المثيل:

(1) الخصائص والطرق الثابتة

TYPESCRIPT
class MathUtils {
  static PI: number = 3.14159;

  static circleArea(radius: number): number {
    return MathUtils.PI * radius ** 2;
  }

  static clamp(value: number, min: number, max: number): number {
    return Math.min(Math.max(value, min), max);
  }
}

// No need to create an instance,Call directly using the class name
console.log(MathUtils.PI);              // 3.14159
console.log(MathUtils.circleArea(5));   // 78.53975
console.log(MathUtils.clamp(150, 0, 100));  // 100

(2) الكتل الثابتة (TypeScript 5.0 / ES2022+)

TYPESCRIPT
class Config {
  static host: string;
  static port: number;

  // Static Initialization Block
  static {
    Config.host = process.env.HOST ?? "localhost";
    Config.port = Number(process.env.PORT) || 3000;
  }
}

(3) الفرق بين العناصر الثابتة وعناصر المثيل

TYPESCRIPT
class Counter {
  static totalCount: number = 0;   // Shared by all instances
  instanceCount: number = 0;       // Each instance is independent

  increment(): void {
    Counter.totalCount++;
    this.instanceCount++;
  }
}

let c1 = new Counter();
let c2 = new Counter();

c1.increment();
c1.increment();
c2.increment();

console.log(`Examples1:${c1.instanceCount}`);  // 2
console.log(`Examples2:${c2.instanceCount}`);  // 1
console.log(`Total:${Counter.totalCount}`); // 3

▶ مثال: فئة مع معدّلات الوصول واختصار المُنشئ

الناتج:

TEXT 📖 للعرض فقط
100C = 212F
0C = 32F
TYPESCRIPT
class Article {
  constructor(
    readonly id: number,
    public title: string,
    private _views: number = 0
  ) {}

  get views(): number {
    return this._views;
  }

  incrementViews(): void {
    this._views++;
  }

  toString(): string {
    return `[${this.id}] ${this.title} (${this.views} views)`;
  }
}

let post = new Article(1, "Hello TypeScript");
post.incrementViews();
post.incrementViews();
console.log(post.toString());  // "[1] Hello TypeScript (2 views)"
// post._views;  // ❌ private — cannot access from outside

الناتج:

TEXT 📖 للعرض فقط
100C = 212F
0C = 32F

▶ مثال: طرق المصنع الثابتة والخصائص للقراءة فقط

الناتج:

TEXT 📖 للعرض فقط
100C = 212F
0C = 32F
TYPESCRIPT
class Point {
  constructor(
    public readonly x: number,
    public readonly y: number
  ) {}

  static origin: Point = new Point(0, 0);

  static fromAngle(angle: number, distance: number): Point {
    return new Point(
      Math.round(distance * Math.cos(angle)),
      Math.round(distance * Math.sin(angle))
    );
  }

  distanceTo(other: Point): number {
    return Math.sqrt((this.x - other.x) ** 2 + (this.y - other.y) ** 2);
  }
}

let p = Point.fromAngle(Math.PI / 4, 10);
console.log(`(${p.x}, ${p.y})`);                // "(7, 7)"
console.log(p.distanceTo(Point.origin));        // "~10"

الناتج:

TEXT 📖 للعرض فقط
100C = 212F
0C = 32F


❓ أسئلة شائعة

س هل private خاص حقًّا أثناء وقت التشغيل؟
ج لا. إن private في TypeScript ما هو إلا فحص يتم في وقت التحويل البرمجي — فلا يزال من الممكن الوصول إلى الخصائص الخاصة في كود JavaScript المُحوَّل. إن بناء الجملة #private في ES2022 (الحقول الخاصة) هو ما يوفر الخصوصية الحقيقية أثناء وقت التشغيل. كما يدعم TypeScript #private: class C { #secret = 1; }.
س متى يجب استخدام private، ومتى يجب استخدام protected؟
ج تُستخدم private لتفاصيل التنفيذ الداخلية التي «تحتاجها الفئة نفسها فقط»؛ بينما تُستخدم protected للأعضاء التي «قد تحتاج الفئات الفرعية أيضًا إلى الوصول إليها أو تجاوزها». إذا كنت غير متأكد، فابدأ بـ private — يمكنك دائمًا تغييرها إلى protected لاحقًا إذا لزم الأمر (فمن الأكثر أمانًا أن تكون أكثر تساهلاً بدلاً من أن تكون أكثر تقييدًا).
س ما الفرق بين طرق الحصول/التعيين (getters/setters) والطرق العادية؟
ج تجعل طرق الحصول/التعيين عملية قراءة وكتابة الخصائص تبدو وكأن الوصول إليها يتم بشكل مباشر (YIJIAN0PH)، لكنها تنفذ منطقًا مخصصًا خلف الكواليس. أما الطرق العادية فتتطلب استدعاءات صريحة (YIJIAN1PH). يُنصح باستخدام طرق الحصول/التعيين للخصائص المعروضة خارجيًا (لإجراء التحقق من الصحة أو حساب الخصائص)، واستخدام الطرق العادية للتنفيذ الداخلي.
س هل يمكن استخدام this في الطرق الثابتة؟
ج في الطرق الثابتة، يمكن استخدام this refers to the فئة itself (not an مثيل). In static create() { return new this(); }, this is equal to the current فئة. However, this may be lost in arrow functions or callbacks—it is recommended to use the فئة name instead of this.

📖 ملخص

📝 تمارين

  1. المشكلة الأساسية (صعوبة ⭐): أنشئ فئة Rectangle (تحتوي على خصائص العرض والارتفاع) وقم بتنفيذ الطريقتين getArea() وgetPerimeter(). قم بتبسيط منشئ الفئة باستخدام الخصائص المعلمة.
  2. مشكلة متقدمة (درجة الصعوبة ⭐⭐): أنشئ فئة BankAccount — اجعل balance خاصًّا، واسمح بإجراء العمليات عبر طرق deposit وwithdraw، واجعل الرصيد متاحًا للقراءة فقط باستخدام دالة getter، وتأكد من كفاية الرصيد قبل إجراء عملية withdraw.
  3. التحدي (الصعوبة: ⭐⭐⭐): قم بتنفيذ فئة عامة Stack<T> — قم بتخزين البيانات في مصفوفة خاصة، ووفر طرق دفع و pop و peek و size، وقم بتنفيذ الخاصية size (للقراءة فقط) باستخدام طرق الحصول (getters)، واستخدم طريقة ثابتة static fromArray<T>(items: T[]): Stack<T> لإنشاء مكدس من المصفوفة.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%