Подтвердить что ты не робот

Расширение и реализация чистого абстрактного класса в TypeScript

Предположим, что у меня есть чистый абстрактный класс (т.е. абстрактный класс без какой-либо реализации):

abstract class A {
    abstract m(): void;
}

Как и в С# и Java, я могу расширить абстрактный класс:

class B extends A {
    m(): void { }
}

Но, в отличие от С# и Java, я также могу реализовать абстрактный класс:

class C implements A {
    m(): void { }
}

Как классы B и C ведут себя по-другому? Почему я должен выбирать один или другой?

(В настоящее время TypeScript handbook и спецификация языка не охватывают абстрактные классы.)

4b9b3361

Ответ 1

реализует ключевое слово рассматривает класс A как интерфейс, это означает, что C должен реализовать все методы, определенные в A, независимо от того, имеют ли они реализацию или нет в A. Также нет вызовов супер-методов в C.

extends ведет себя так же, как ожидалось от ключевого слова. Вы должны реализовать только абстрактные методы, и супервызывы доступны/сгенерированы.

Я думаю, что в случае абстрактных методов это не имеет значения. Но у вас редко есть класс только с абстрактными методами, если вы сделаете это, было бы гораздо лучше просто преобразовать его в интерфейс.

Вы можете легко увидеть это, посмотрев сгенерированный код. Я сделал здесь пример детской площадки .

Ответ 2

Основываясь на ответе @toskv, если вы расширяете абстрактный класс, вы должны вызвать super() в конструкторе подкласса. Если вы реализуете абстрактный класс, вам не нужно вызывать super() (но вы должны реализовать все методы, объявленные в абстрактном классе, включая закрытые методы).

Реализация абстрактного класса вместо расширения может быть полезна, если вы хотите создать фиктивный класс для тестирования, не беспокоясь об исходных зависимостях класса и конструкторе.

Ответ 3

Меня привели сюда, потому что я только что задавал себе тот же вопрос, и, читая ответы, я понял, что выбор также повлияет на оператор instanceof.

Поскольку абстрактный класс является фактическим значением, которое передается в JS, его можно использовать для проверок во время выполнения, когда подкласс расширяет его.

abstract class A {}

class B extends A {}

class C implements A {}

console.log(new B() instanceof A) // true
console.log(new C() instanceof A) // false

Ответ 4

В примере расширений, которые вы даете, вы фактически не добавляете ничего нового в класс. Таким образом, оно не распространяется ни на что. Хотя расширение ничем не является допустимым Typescript, мне кажется, что в этом случае "орудия" были бы более уместными. Но в конце концов они эквивалентны.