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


78

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

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

Як і в C # та Java, я можу розширити абстрактний клас:

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

Але на відміну від C # та Java, я також можу реалізувати абстрактний клас:

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

Як заняття Bта Cповедінка по-різному? Чому я вибрав би одне проти іншого?

(На даний момент довідник TypeScript та специфікація мови не охоплюють абстрактні класи.)


2
Зараз у підручнику з TypeScript є розділ «Абстрактні класи». typescriptlang.org/docs/handbook/classes.html Дякую за це запитання! Я не мав уявлення про abstractдоступність у TS, і це допомогло мені це зрозуміти.
theUtherSide

Досить дивно, що документи, на які посилається @theUtherSide, якимось чином не мають жодного прикладу class C implements A. Я навіть не знаю , що це було можливо до тих пір , читаючи ці пости, і я був в Ts документах багато в останнім часом.
kevins

Відповіді:


101

Реалізує ключових слів : трактує класу А , як інтерфейс, що кошти C повинен реалізувати всі методи не визначені в А , незалежно від того , якщо у них є реалізація чи ні в А . Також у C немає викликів супер методів .

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

Я думаю, що у випадку абстрактних методів це не має значення. Але у вас рідко є клас із лише абстрактними методами, якщо ви це зробите, було б набагато краще просто перетворити його на інтерфейс .

Ви можете легко переконатися в цьому, переглянувши згенерований код. Я зробив тут приклад дитячого майданчика .


12
Якщо Aце чисто абстрактний клас, можливо, єдиною помітною відмінністю є поведінка instanceofключового слова? Я згоден, що інтерфейси, мабуть, будуть кращими, ніж чисто абстрактні класи. Однак у Angular 2 лише останні можна використовувати як маркери постачальника DI.
Michael Liu

1
справді, дякую, що помітили екземпляр речі, я додаю його до відповіді для завершення (ви можете внести зміни, якщо хочете). Що стосується angular2, то, мабуть, це специфічна проблема angular2. :)
toskv

2
@toskv, дякую за опис застосовності ключового слова 'implements' до інтерфейсів AND класу. Наприклад, AngularJS 2.0 використовує це для реалізації свого класу 'OnInit' (а не 'інтерфейсу'). Я озирнувся, чи маєте ви посилання на це. Я не бачу цього чітко в документації TS.
MoMo

@toskv знайшов посилання в github @ github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.9.4 .
MoMo

18

Мене сюди привели, бо я щойно задавав собі те саме питання, і під час читання відповідей мені здалося, що вибір також вплине на 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

Дякую @Tao, це чистий і добре пояснений. Також я хочу додати додаткову інформацію для цього, відняти чи ні, не важливо, якщо ви видалите абстрактні ключові слова, ви отримаєте той самий результат.
Доган

10

Спираючись на відповідь @ toskv , якщо ви розширюєте абстрактний клас, вам доведеться викликати super()конструктор підкласу. Якщо ви реалізуєте абстрактний клас, вам не потрібно викликати super()(але ви повинні реалізувати всі методи, оголошені в абстрактному класі, включаючи приватні методи).

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


0

У прикладі розширень, які ви надаєте, ви насправді не додаєте нічого нового до класу. Тож він нічим не продовжений. Незважаючи на те, що розширення нічим не є дійсним Typescript, мені здається, що в цьому випадку "реалізації" були б більш доречними. Але в кінці дня вони еквівалентні.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.