Menu

מחלקה אבסטרקטית ב-TypeScript: מתודות, מאפיינים ו-interface

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

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

מחלקה אבסטרקטית היא מחלקת בסיס שמסומנת ב-abstract. אי אפשר ליצור אותה עם new, והיא יכולה להצהיר על מתודות abstract בלי גוף, שכל תת-מחלקה חייבת לממש.

Shape משתפת את describe() עם כל תתי-המחלקות ומחייבת כל אחת מהן לספק את area(). הטיפוס Shape[] מחזיק כל שילוב של תתי-מחלקות.

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

קריאה ל-new על מחלקה אבסטרקטית היא שגיאת קומפילציה, כי לאובייקט היו מתודות בלי מימוש:

index.ts(6,11): error TS2511: Cannot create an instance of an abstract class.

זה כלל של זמן קומפילציה. abstract נמחק מהפלט, כך ש-Shape שנוצרת היא מחלקת JavaScript רגילה, וקוד JavaScript בלי טיפוסים עדיין יכול לקרוא ל-new Shape(). כשספרייה צריכה הגנה בזמן ריצה, הבנאי יכול לבדוק את new.target:

מתודות ומאפיינים אבסטרקטיים

תת-מחלקה חייבת לממש כל איבר אבסטרקטי, או להיות אבסטרקטית בעצמה. אם אחד חסר, מקבלים את השגיאה TS2515, שנראית כמו Non-abstract class 'Square' does not implement inherited abstract member area from class 'Shape', או TS2654 שמפרטת את כולם כשחסרים כמה.

שדות, getters ומתודות יכולים כולם להיות אבסטרקטיים, והם יכולים להיות protected:

למתודה אבסטרקטית אין גוף; כתיבת גוף היא השגיאה TS1245 (Method 'x' cannot have an implementation because it is marked abstract). מחלקה אבסטרקטית לא חייבת לכלול איברים אבסטרקטיים בכלל: abstract לבדו רק מונע יצירת מופע ישירה.

תבנית template method

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

מחלקות אבסטרקטיות יכולות להיות גנריות, כמו כאן, כך שכל תת-מחלקה בוחרת את טיפוס הרשומה.

טיפוסי בנאי אבסטרקטיים

typeof Shape של מחלקה אבסטרקטית הוא בנאי שאסור לקרוא לו, ולכן פרמטר מטיפוס typeof Shape לא יכול לעשות new c(). כשפונקציה צריכה לקבל מחלקות אבסטרקטיות (למשל כדי לרשום אותן או לבדוק instanceof), תנו לה טיפוס עם חתימת בנייה אבסטרקטית:

abstract new מקבל גם מחלקות אבסטרקטיות וגם מחלקות קונקרטיות; new רגיל מקבל רק קונקרטיות.

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

מחלקה אבסטרקטיתInterface
מכילה קודכן: מתודות, אתחול שדות, בנאילא, רק טיפוסים
קיימת בזמן ריצהכןלא, נמחקת
instanceofעובדלא אפשרי
מחלקה יכולה להשתמש באחת (extends)הרבה (implements)
מגדירי גישהprivate, protected, publicרק איברים ציבוריים
טיפוס לאובייקטים רגיליםרק אם אין לה איברי private/protected, ואז instanceof נכשלכן, כל ערך עם המבנה הזה

כלל האצבע: interface כשצריך רק לתאר מבנה (המקרה הנפוץ ביותר, והוא עובד גם עם אובייקטים ליטרליים), ומחלקה אבסטרקטית כשתתי-המחלקות חולקות מימוש אמיתי ורוצים שהקומפיילר יחייב אותן להשלים את החסר. השתיים משתלבות היטב: interface לחוזה הציבורי, ומחלקה אבסטרקטית כבסיס נוח אחד שמממש אותו. ראו interface מול type להשוואה הנפוצה השנייה.

טעויות נפוצות

  • שימוש במחלקה אבסטרקטית כש-interface מספיקה. אם אין קוד במחלקת הבסיס, היא בעצם interface עם משקל נוסף בזמן ריצה ומגבלה של ירושה יחידה.
  • ניסיון לכתוב static abstract. אסור. איברים סטטיים לא יכולים להיות אבסטרקטיים.
  • ציפייה לשגיאת זמן ריצה מ-new על מחלקה אבסטרקטית. אין כזו, אלא אם כותבים את הבדיקה של new.target.
  • קריאה למתודה אבסטרקטית מהבנאי של מחלקת הבסיס. היא רצה לפני שהשדות של תת-המחלקה מאותחלים, ולכן המימוש רואה אותם כ-undefined.

שאלות נפוצות

מה זו מחלקה אבסטרקטית ב-TypeScript?

מחלקה שמסומנת ב-abstract, שאי אפשר ליצור אותה עם new, ושיכולה להצהיר על איברים abstract בלי מימוש. תתי-מחלקות חייבות לממש כל איבר אבסטרקטי. זו דרך לשתף קוד ולדרוש מבנה מסוים באותו זמן.

מה ההבדל בין מחלקה אבסטרקטית ל-interface ב-TypeScript?

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

האם למחלקה אבסטרקטית יכול להיות בנאי ב-TypeScript?

כן. הוא רץ כשתת-מחלקה קוראת ל-super(...). עדיין אי אפשר לקרוא ל-new על המחלקה האבסטרקטית עצמה (TS2511: Cannot create an instance of an abstract class).

האם מתודות סטטיות יכולות להיות אבסטרקטיות ב-TypeScript?

לא. abstract חל רק על איברי מופע; static abstract הוא השגיאה TS1243 ('static' modifier cannot be used with 'abstract' modifier). כדי לדרוש מבנה סטטי, תנו לבנאי טיפוס של interface שכולל את האיבר הסטטי ובדקו את המחלקה מולו.

האם מחלקה אבסטרקטית נאכפת בזמן ריצה?

לא. abstract נמחק, כך שהמחלקה המקומפלת היא JavaScript רגיל, וקוד JavaScript רגיל עדיין יכול לקרוא עליה ל-new. אם זה חשוב, בדקו את new.target בבנאי וזרקו שגיאה.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל