מחלקות

מחלקות ב-TypeScript הן אותן מחלקות של JavaScript, עם טיפוסים לשדות ולמתודות, והרשאות גישה. מי שלמד OOP ב-Java ירגיש בבית.

מחלקה עם טיפוסים

class BankAccount {
    owner: string;
    private balance: number;

    constructor(owner: string, initialBalance = 0) {
        this.owner = owner;
        this.balance = initialBalance;
    }

    deposit(amount: number): void {
        if (amount <= 0) throw new Error('סכום חייב להיות חיובי');
        this.balance += amount;
    }

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

const account = new BankAccount('דנה', 100);
account.deposit(50);
account.balance = 1_000_000;
// Property 'balance' is private and only accessible within class 'BankAccount'.

הרשאות גישה

מילהנגיש מ-
public (ברירת מחדל)כל מקום
protectedהמחלקה ומחלקות שיורשות ממנה
privateהמחלקה בלבד (בדיקה של TypeScript)
#fieldהמחלקה בלבד, גם בזמן ריצה (JavaScript אמיתי)
readonlyנקבע בבנאי ולא משתנה

private של TypeScript נעלם אחרי הסרת הטיפוסים. אם הפרטיות חשובה באמת (ספרייה, נתון רגיש), #balance של JavaScript אוכף אותה גם בזמן ריצה.

implements: מחלקה שמקיימת חוזה

type Notifier = {
    send(to: string, message: string): Promise<void>;
};

class EmailNotifier implements Notifier {
    async send(to: string, message: string) {
        console.log(`מייל ל-${to}: ${message}`);
    }
}

class SmsNotifier implements Notifier {
    async send(to: string, message: string) {
        console.log(`SMS ל-${to}: ${message}`);
    }
}

// הקוד עובד מול החוזה, לא מול מחלקה ספציפית
async function remind(notifier: Notifier, to: string) {
    await notifier.send(to, 'תזכורת: הפגישה מחר');
}

ירושה ומחלקה אבסטרקטית

abstract class Shape {
    abstract area(): number;

    describe(): string {
        return `שטח: ${this.area().toFixed(2)}`;
    }
}

class Circle extends Shape {
    constructor(private readonly radius: number) {
        super();
    }

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

new Shape();
// Cannot create an instance of an abstract class.
new Circle(2).describe();   // 'שטח: 12.57'

private readonly radius בפרמטר של הבנאי הוא קיצור: מגדיר שדה וממלא אותו, בשורה אחת. שימו לב: זה עוד תחביר שלא עובד כשמריצים .ts ישירות ב-Node.js (כי צריך לייצר בו קוד), ולכן בפרויקטים כאלה כותבים את השדה במפורש.

מחלקות או פונקציות ואובייקטים?

ב-JavaScript מודרני, ובמיוחד ב-React, רוב הקוד כתוב בפונקציות ואובייקטים פשוטים. מחלקות מתאימות כשיש מצב פנימי עם כללים (כמו חשבון בנק שלא יכול לרדת מתחת לאפס), או כשספרייה דורשת אותן. שני הסגנונות לגיטימיים, והעיקר לא לערבב בלי סיבה.

בדקו את עצמכם

נסו לענות לבד לפני שאתם פותחים את התשובה.

  1. מה ההבדל בין private ל-#field?

    1. #field רק לקריאה
    2. private מהיר יותר
    3. private נבדק רק על ידי TypeScript, #field פרטי גם בזמן ריצה
    4. אין הבדל
    הצגת התשובה

    תשובה ג. private נמחק עם הטיפוסים, ואילו # הוא תכונה של JavaScript עצמה.

  2. מה עושה implements?

    1. מוודא שהמחלקה מקיימת את החוזה של הטיפוס
    2. יוצר מופע
    3. יורש קוד
    4. מייבא קובץ
    הצגת התשובה

    תשובה א. המהדר בודק שכל המתודות והשדות הנדרשים קיימים.