Typescript: клас срещу интерфейс

Интерфейсът и класът имат различна дефиниция, или да говорим за Java или Typescript

Искам да се справя с проблем, който днес видях твърде много. В кода за писане тук е това, което открих:

клас MyClass {
  номер;
  b: низ;
}

НЕ ! Просто не. Боли. Но това, което наистина боли, е след това да прочетете:

клас MyOtherClass разширява MyClass {
  в: номер;
}

Арга! Знам, че може да бъде объркващо за хора, идващи от OOP език, но в Javascript обект НЕ е екземпляр от клас. Работя с C ++ от около десет години, така че разбирам, че се чувства добре, когато го правя

нека мина = нов MyClass ();

получавате „обект“. Но когато мислите, че забравяте, че Javascript не е език, базиран на класа, той използва прототипен подход. (прочетете статията по-долу или каквото и да е друго обяснение за това, за да разберете как работи всичко това).

интерфейс

Един от основните принципи на TypeScript е, че проверката на типа се фокусира върху формата, която имат стойностите.

Интерфейсите са договори. Интерфейс дефинира какво има вътре в обекта (отново ... не е екземпляр от клас). Когато дефинирате вашия интерфейс

интерфейс MyInterface {
  номер;
  b: низ;
}

Казвате, че всеки обект на този договор трябва да бъде обект, съдържащ 2 свойства, които се наричат ​​конкретно „a“ и „b“ и съответно са число и низ.
Случва се, че typecript ще хвърли грешка по всяко време, когато не спазвате този договор (например, ако параметър на функция трябва да бъде MyInterface, не можете да предавате нищо друго).

клас

Нека да разгледаме първите редове на определението в клас според документа на TS:

Традиционният JavaScript използва функции и базирани на прототип наследяване за изграждане на компоненти за многократна употреба, но това може да се почувства малко неудобно за програмистите, които са по-удобни с обектно-ориентиран подход, където класовете наследяват функционалността и обектите се изграждат от тези класове.

Първият ред от дефиницията на клас в TS е „базирано на прототип наследяване е объркващо за програмистите, идващи от света на OOP“. След това стигам до мисленето „това е основната причина класовете да съществуват в TS“ (но това е може би само аз).
Както знаете, Typescript се превежда на Javascript, който също използва ключова дума "class" от съвсем скоро.
Нека да видим MDN документа относно класовете в Javascript:

JavaScript класовете, въведени в ECMAScript 2015, са предимно синтактична захар над съществуващото наследствено основано на прототип JavaScript. Синтаксисът на клас не въвежда нов JavaScript, обектно-ориентиран модел на наследяване към JavaScript.

Не можете да бъдете по-ясни за класовете в JS (и като разширение, в TS).

Интерфейс срещу клас

Когато определяте договор, искате да използвате интерфейс. Това е всичко, без да спорите за това ... но тогава, кога да използвате клас?
Джон Папа има своето определение в тази статия:

  • Създаване на множество нови инстанции
  • Използване на наследство
  • Единични обекти

Човек може да се съгласи или не е съгласен, но както той казва: „класовете са хубави, но не са необходими в Javascript“. Бих казал, тъй като те са тук и улесняват живота на много хора, можете да ги използвате по каквато и да е причина, която искате, стига да имате предвид, че все още има JS и прототипи.

Но тогава защо агресивното интро?

Защо използването на клас за дефиниране на договор боли

На уебсайта Typescript има страхотно средство, наречено „Playground”

Вие пишете код на машинопис вляво и той ви показва javascript, в който ще се трансформира вдясно.
Нека опитаме с два класа, като един наследи от предишния:

TS код:

JS код:

Е, това е много JS код!

Какво ще кажете за същия договор, но с интерфейси:

TS код:

JS код: Нищо! Тъй като TS използва интерфейси само за да разбере дали спазвате договорите „по време на компилиране“, той не се превежда на нищо в JS (обратно на класовете).
Така че, когато видя клас, дефиниращ договор, всъщност виждам първото изображение в главата си ... и това боли.
Между другото, файл с само интерфейси в него е празен файл в края на деня ...