2.07.20193 min

Kamil Kiełbasa.NET Developer

TypeScript – implementacja interfejsu konstruktora

Dowiedz się, po co i jak krok po kroku stworzyć interfejs dla konstruktora klasy w TypeScript.

TypeScript – implementacja interfejsu konstruktora

Rozpoczynając swoją aktualną pracę, w pewien sposób pożegnałem się z tematami frontend-owymi. Wiadomo - nie postawiłem grubej, czerwonej, nieprzekraczalnej linii, ale po prostu zajmuje się tym zdecydowanie rzadziej. Ostatnio jednak natrafiłem na zagadnienie, które zdecydowanie mnie zainteresowało, mianowicie tworzenie interfejsu dla konstruktora klasy w TypeScript. Od razu zaznaczam, że nie będę w tym artykule omawiał konfiguracji środowiska pod aplikację. Jeżeli to Wasze pierwsze spotkanie z tą technologią polecam Wam:


Interfejsy takie piękne

Od pierwszych chwil, kiedy zacząłem pracować z TypeScript'em, spodobało mi się pisanie interfejsów. Wiecie, niektórzy lubią szybkie samochody, inni interfejsy. Pozwalają hermentyzować szczegóły implementacyjne klas, co pozytywnie wpływa na końcową jakość naszego kodu. W językach niższego poziomu takich jak C#, Java etc. nie wyobrażam sobie większej aplikacji bez użycia interfejsów.

Przykładowy interfejs w TypeScript'cie wygląda następująco:

export interface ICar {
    drive (miles: number): boolean;
}


Widać tu liczne nawiązania do składni ES6. Oczywiście w JavaScript nie istnieje taki byt, jak interfejs, więc po skompilowaniu powyższego kodu otrzymamy całe nic… zero, nie powstanie nawet jedna linijka kodu.

Pewnie zastanawiacie się, w jakim celu dokładać sobie pracy, jeżeli nie będzie żadnego odzwierciedlenia w kodzie wynikowym? Sprawdzanie poprawności implementacji interfejsów, tak samo jak sprawdzanie poprawności typów przekazywanych jako parametr etc. przebiega na poziomie kompilatora TypeScript-a. Dzięki temu o wielu błędach możemy dowiedzieć się od kompilatora, a nie od klienta.

Sama składnia do interpretacji interfejsu w klasie nie musi być trudna. Poniżej przedstawiam najprostszy przykład, na jaki wpadłem.

export class Car implements ICar {
    drive(miles: number): boolean {
        return true;
    }
}


Rysa na szkle

Wszystko super, prosto, przyjemnie, ale… No właśnie to ‘ale’ to clue całego artykułu. Ostatnio pracowałem nad projektem, w którym front-end jest pisany w czystym TypeScript'cie. Nie ma tam żadnego Reacta, Vue, Angulara - jest tylko sam kod. No i tak pracując sobie jak nigdy nic, zauważyłem małą wadę interfejsów TypeScripte'a. Stworzenie takowego zawierającego deklarację konstruktora jest dość… hmmm… skomplikowane.

TypeScript nawet zawiera specjalną składnię, aby móc w interfejsie zdefiniować konstruktor:

export interface ICar {
    new(engine: Engine): ICar;
}


Niestety, próbując zaimplementować ten interfejs, otrzymamy błąd. Możecie to zobaczyć w specjalnie przygotowanym przez mnie linku, który poprowadzi Was do edytora na stronie TypeScript-a.

Przejdźmy teraz do tego, co misie lubią najbardziej i nie, nie do kakałka, a obejścia problemu jak największym łukiem.


Factory na pomoc

Moim sposobem na posiadanie interfejsu z konstruktorem jest wykorzystanie fabryki. W najprostszej postaci wystarczy nam pojedyncza funkcja, która posłuży do wytwarzania obiektów klasy Car. Jednocześnie musimy wynieść deklaracje konstruktora do zewnętrznego interfejsu.

export interface CarConstructor {
    new(engine: Engine): Car;
}
export function CarFactory(ctor: CarConstructor, engine: Engine): Car {
    return new ctor(engine);
}


Coś takiego jest nawet opisane w dokumentacji TypeScript'a. Teraz, jeżeli chcemy utworzyć obiekt klasy Car, wystarczy:

let engine = new Engine();
let car = CarFactory(Car, engine);


Dlaczego?

Teraz pytanie, dlaczego musimy robić takie sztuczki? Z jednej strony chowamy wewnętrzne szczegóły instancjonowania klasy Car, aczkolwiek odczuwamy (tak, wszyscy odczuwamy) lekki zawód z braku możliwości implementacji interfejsu z konstruktorem.

Kompilator TypeScript sprawdza tylko instancję klasy, nie część statyczną. A co się pod nią kryje? Między innymi konstruktor. Kompilator go nie sprawdzi, więc nie będzie wiedział, czy jego implementacja jest poprawna.


Mam nadzieje, że artykuł się przyda :)

<p>Loading...</p>

Powiązane artykuły

Dziel się wiedzą ze 160 tysiącami naszych czytelników

Zostań autorem Readme

Simple SA

Java Developer (Mid/Senior)

medium

7 000 - 15 000 PLN

Kontrakt B2BUmowa o pracę

Praca zdalna 100%

Ważna do 26.02.2022

Dobrze
JavaSpringSpring Boot

Asseco Poland S.A.

Administrator / Starszy Administrator Systemów IT

medium

Brak widełek

Kontrakt B2BUmowa o pracę

Praca zdalna 100%

Ważna do 26.02.2022

Dobrze
PostgreSQLBash

Nokia

5G Automation Engineer, IODT

medium

Brak widełek

Umowa o pracę

Wrocław

Praca zdalna 100%

Ważna do 13.03.2022

Divante

Senior Vue.js Developer

senior

15 300 - 23 500 PLN

Kontrakt B2BUmowa o pracę

Wrocław

Praca zdalna 100%

Ważna do 13.03.2022

Dobrze
JavaScriptTypeScriptVue.js

T-Mobile Polska S. A.

Frontend Developer

medium

Brak widełek

Kontrakt B2B

Warszawa

Ważna do 26.02.2022

Bardzo dobrze
ReactReduxNode.js

Commerzbank - Centrum Technologii Cyfrowych w Polsce

Business Expert for Risk Applications

medium

Znamy widełki

Umowa o pracę

Łódź

Ważna do 26.02.2022

Dobrze
SQLMS Office
Początkująco
SAS / R / Python

Commerzbank - Centrum Technologii Cyfrowych w Polsce

Business Expert with German for Risk Analytics

medium

Znamy widełki

Umowa o pracę

Łódź

Ważna do 26.02.2022

Dobrze
MS Office
Początkująco
SQL / VBA / PythonQlik Sense / Qlik View / Arcadia

Hitachi Energy

Quality Assurance Engineer

medium

8 000 - 14 000 PLN

Umowa o pracę

Kraków

Ważna do 26.02.2022

Dobrze
automation testing .NET CoreSelenium
Początkująco
MS SQL

Commerzbank - Centrum Technologii Cyfrowych w Polsce

Business Expert with German for Risk Applications

medium

Znamy widełki

Umowa o pracę

Łódź

Ważna do 26.02.2022

Dobrze
MS OfficeSQL
Początkująco
SAS / R / Python