Расширение и реализация чистого абстрактного класса в 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 и спецификация языка не охватывают абстрактные классы.)
Ответы
Ответ 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, мне кажется, что в этом случае "орудия" были бы более уместными. Но в конце концов они эквивалентны.