TypeScript - למה נדרש שמחלקות אבסטרקטיות יממשו ממשקי שמות באופן מלא?


בהנחה שיש לי את הממשק הזה:

export class interface State {
  default(): void;
}

והמחלקה המופשטת הזו:

export abstract class BaseState implements State {}

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

אני יודע שאני יכול לעשות

export abstract class BaseState implements State {
  abstract default(): void;
}

אבל זה בהחלט לא DRY. אז, האם יש סיבה טובה להיות את ההתנהגות הזו ב-TypeScript?

תשובה #1

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

אם אתם לא רוצים לקבל אזהרה לגבי זה, אתם יכולים פשוט לדלג על הסימון implements State.

דוגמה... אני משתמש בממשק Example כדי לוודא שהאובייקט שנשלח ל-usesExample שלי הוא תקין... אני מקבל בטיחות סוגים לאורך כל הדרך, ואני לא צריך להכניס מימוש מופשט של method במחלקה המופשטת שלי.

יכולתי (באופן אופציונלי) להוסיף את הממשק Example ל-SubExample אם רציתי שיקום להודיע לי אם שכחתי להוסיף משהו... אבל השורה שמשתמשת ב-usesExample הייתה עושה זאת בכל מקרה.

interface Example {
    method(): string;
}

abstract class BaseExample {
    abstract foo(): string;
}

class SubExample extends BaseExample {
    foo() {
        return '';
    }

    method() {
        return '';
    }
}

function usesExample(example: Example) {
    return example.method();
}

usesExample(new SubExample());