TypeScript - חלק ב': איך כותבים Class

בהמשך לפוסט הקודם על סוגי משתנים ב-TypeScript, בפוסט זה אסביר על איך כותבים Class. 

TypeScript הופך את כתיבת ה-Class להרבה יותר נוח לכתיבה ובטוח לשימוש בהשוואה ל-JavaScript, מכיוון שהוא מאפשר לנו לכתוב בצורה שיותר מוכרת לנו משפות תכנות אחרות כולל בנאים ומאפיינים ובנוסף הוא מוודא שכל שימוש ב-Class נעשה בצורה נכונה: שסוג המשתנים מתאים למה שהגדרנו ודרשנו מהלקוחות של ה-Class שבנינו, שלא יוצרים Class ללא השדות שהם חובה וכו'.

 

איך כותבים Class ב- TypeScript

class היא מילת מפתח ב-TypeScript ועל ידי כתיבה לפני שם ה-Class נגדיר אותו.

לדוגמא, נכתוב Class שיתאר כלב.

class Dog {

}

ה-Class שלנו בשם Dog לא עושה כרגע שום דבר, הוא פשוט מבנה ללא פונקציות או מאפיינים, אך במידה ונביט בקוד ה-JavaScript שנוצר על ידי קימפול קוד ה-TypeScript שכתבנו, נוכל לראות שכבר נקבל את המבנה של Class ב- JavaScript שנראה כך:

var Dog = (function () {
    function Dog() {
    }
    return Dog;
}());

 

כעת נראה איך מוספים לו פונקציונליות.

 

הוספת משתנים ל-Class ב- TypeScript

בדומה להגדרת משתנה ב- TypeScript, גם במקרה של Class ניתן להגדיר את סוג משתנה שאנו מגדירים ל-Class.

לדוגמא, נוסיף מספר משתנים ל- Dog: את שמו (name) ואת המזון המועדף עליו (favoriteFood) כאשר שניהם יהיו מסוג מחרוזת (string):

class Dog {
    name: string;
    favoriteFood: string;
}

 

בקוד הבא נוכל לראות איך אנחנו משתמשים ב-Class החדש על ידי הגדרת המשתנה (lassie) מסוג Dog (בשורה הראשונה), כך שבשרות 2-3 נוכל לערוך את השם (Lassie) והמזון המועדף (Bonzo) על הכלב החדש שלנו:

var lassie: Dog = new Dog();
lassie.name = 'Lassie';
lassie.favoriteFood = 'Bonzo';

 

שימו לב שרמת ההרשאות למשתנה כברירת המחדל היא public, אפשר לרשום את מילת המפתח public אם אנחנו רוצים שזה יהיה ברור למי שיקרא את הקוד.

על מנת לחסום גישה למשתנה מחוץ ל-class יש לרשום לפני שם המשתנה את מילת המפתח private.

חוץ מ-public ו-private קיימת גם רמת ההרשאה protected אשר מאפשרת להשתמש במשתנה גם ביורשים של ה-Class, אך ירושה של Class ב-TypeScript היא לא חלק מפוסט זה ואולי נרחיב עליו בפוסט אחר. 

 

 

 

הוספת בנאי (Constructor) ל-Class ב- TypeScript

מכיוון שאחנו לא רוצים שכל אחד יוכל פשוט להגדיר כלב בלי שם או שלא נדע מה האוכל שהוא אוהב לאכול, נגדיר ל-Class שלנו Constructor

 הוספת בנאי (Constructor) נעשית באמצעות מילת המפתח constructor ולאחר מכן שמות הפרטרים שנרצה להעביר, ואם נרצה, ניתן גם להעביר את סוג הפרמטים.

במקרה הספציפי שלנו לא חייבים להגדיר לפרמטרים של הבנאי את סוג המשתנים מפני שכבר הגדרנו את הסוג של המשתנים ו- TypeScript יודע כבר להגדיר אותם אוטומטית, ולכן, גם במידה ולא נגדיר את סוג הפרמטר בבנאי, TypeScript יחזיר שגיאה במידה ונעביר סוג משתנה ששונה מ-string.

בקוד הבא ניתן לראות את ה-Class שלנו עם הבנאי החדש:

class Dog {
    name: string;
    favoriteFood: string;
    
    constructor(pName: string, pFavoriteFood:string) {
        this.name = pName;
        this.favoriteFood = pFavoriteFood;
    }
}

 

במידה ונרצה לאפשר להגדיר כלב ללא favoriteFood ניתן להוסיף את הפרמטר pFavoriteFood כאופציונלי באמצעות סימן שאלה לאחר שם הפרמר ולהגדיר ערך ברירת מחדל במידה והוא לא מועבר לנו בבנאי כך:

class Dog {
    name: string;
    favoriteFood: string;
    
    constructor(pName: string, pFavoriteFood?:string) {
        this.name = pName;
        this.favoriteFood = pFavoriteFood|| 'Whatever I find';
    }
}

כעת אצור שני כלבים באמצעות הבנאי, לאסי ופפסי. לאסי אוהבת לאכול בונזו ולפפסי אין מזון מועדף והוא יאכל כל דבר שהוא ימצא. לאחר מכן תוכלו לראות את התוכן של כל אחר מהם שהדפסתי באמצעות console.log.

var lassie: Dog  = new Dog('Lassie', 'Bonzo');
var pepsi: Dog = new Dog('Pepsi');
console.log(lassie);    // Dog {name: "Lassie", favoriteFood: "Bonzo"}
console.log(pepsi);     // Dog {name: "Pepsi", favoriteFood: "Whatever I find"}

 

 שימו לב ש-TypeScript לא מאפשר הגדרה של מספר בנאים, כלומר, ניתן להגדיר לכל Class בנאי אחד בלבד.

לכן, במידה ואתם צריכים מספר בנאים מומלץ להשתמש בפרמטר אופציונלי

 

 

 

הוספת פונקציה ל-Class ב- TypeScript

 כעת נכתוב פונקציה שתקפיץ הודעה על המסך (alert). נקרא לפונקציה speak ומכיוון שרוב הכלבים נובחים היא תרשום Bark.

class Dog {
    name: string;
    favoriteFood: string;
    
    constructor(pName: string, pFavoriteFood?:string) {
        this.name = pName;
        this.favoriteFood = pFavoriteFood|| 'Whatever I find';
    }

    speak() {
        alert('Bark');
    }
}

 

 

 

הגדרת מאפיינים (Properties) ל-Class ב- TypeScript

לאחר שבהתחלה הוספנו את המאפיינים ל-Class בצורה שמאפשרת למשתמש לשנות אותם מתי שהוא רוצה אנחנו נשנה אותם שיהיו נגישים רק לקריאה או לכתיבה באמצעות Accessors. את שם הכלב לא נאפשר לשנות לאחר ההגדרה הראשונית בבנאי אך נאפשר לקרוא אותו באמצעות getter, ואת המזון המועדף נאפשר ולקרוא באמצעות getter ולשנות באמצעות setter כדי לוודא שלא מכניסים לנו ערך שהוא undefined.

 

בתור התחלה אשנה את רמת ההרשאה של המשתנים שלי ל- private ואשנה להם את השם כך שאוכל להמשיך להתייחס אליהם בשם הישן.

זה אמור להיות מוכר למי שעבד ב- C Sharp עם מאפיינים, למי שלא, אסביר בקצרה שאנחנו מגדירים משתנים ופונקציה שתעטוף את הגישה אליהם, לכן אשנה את השם של המשתנה קלות ואני יוסיף לו בהתחלה את התו _.

לאחר מכן נוסיף פונקציית get עבור name ופונקציית get עבור favoriteFood אשר יחזירו את המשתנים שאנו מסתירים.

כמו כן נוסיף פונקציית set עבור favoriteFood אשר תבדוק שהערך שהמשתמש מנסה להגדיר הוא לא ריק, אם כן נגדיר ערך ברירת מחדל (Whatever I find) כפי שהיה לנו בבנאי.

לאחר כל השינויים ה-Class שלנו יראה כך:

class Dog {
    private _name: string;
    private _favoriteFood: string;

    get name(): string {
        return this._name;
    }

    get favoriteFood(): string {
        return this._favoriteFood;
    }

    set favoriteFood(pfavoriteFood: string)  {
        this._favoriteFood = pfavoriteFood || 'Whatever I find';
    }  
    
    constructor(pName: string, pfavoriteFood?:string) {
        this._name = pName;
        this.favoriteFood = pfavoriteFood;
    }

    speak() {
        alert('Bark');
    }
}

שימו לב שגם הבנאי שלנו יפנה כעת למשתנה של שם הכלב בשמו החדש _name אך במקרה של המשתנה השני של המזון המועדף נקרא ל-setter של favoriteFood על מנת שגם בבנאי נעשה בדיקה על הערך שאנחנו מקבלים בשדה זה.

כעת, אני יוסיף מספר קריאות ל-Class שלנו ואציג את התוצאות בהערה:

var lassie: Dog = new Dog('Lassie', 'Bonzo');
var pepsi: Dog = new Dog('Pepsi');
console.log(lassie);    // Dog {_name: "Lassie", _favoriteFood: "Bonzo"}
console.log(pepsi);     // Dog {_name: "Pepsi", _favoriteFood: "Whatever I find"}

pepsi.favoriteFood = 'Royal Canin';
console.log(pepsi);     // Dog {_name: "Pepsi", _favoriteFood: "Royal Canin"}

pepsi.name = 'Rocky'; // Error (Left- hand side of assignment expression cannot be a constant or a read- only property.)

 

 שימו לב שאני יכול לשנות את המזון המועדף של הכלב פפסי אך לא את שמו (במקרה זה אקבל שגיאת קומפילציה).

 

 

תגיות:

הוסף תגובה