
w tym wpisie na blogu przedstawię koncepcję interfejsów i jak mogą być przydatne nawet w językach dynamicznych. Skorzystam również z implementacji biblioteki.js to bring the concept to JavaScript, and show you how to get some extra utility out of interfaces.
Google definiuje interfejs jako „punkt, w którym dwa systemy, podmioty, organizacje itp. meet and interact”, a ta definicja odnosi się do interfejsów w programowaniu. W rozwoju oprogramowania interfejs jest strukturą wymuszającą określone właściwości obiektu — w większości języków obiekt ten jest klasą.
oto przykład interfejsu w Javie:
w powyższym przykładzie interfejsCar
opisuje klasę, która ma dwie metody bez zwracanego typu, z których obie przyjmują pojedynczy argument integer. Szczegóły implementacji każdej funkcji pozostawia się klasie, dlatego obie metody nie mają ciała. Aby upewnić się, że klasa implementuje interfejsCar
, używamy słowa kluczowego implements
:
Interfejsy w JavaScript
Interfejsy nie są czymś w JavaScript, nie tak naprawdę. JavaScript jest językiem dynamicznym, w którym typy są zmieniane tak często, że programista może nawet nie zdać sobie sprawy, z tego powodu ludzie twierdzą, że nie ma potrzeby dodawania interfejsu do standardu ECMAScript, na którym oparty jest JavaScript.
jednak JavaScript rozwinął się masowo jako język zaplecza w postaci węzła.js, a z tym wiążą się różne wymagania i inny tłum, który może mieć inne zdanie. Aby dodać do tego, język szybko staje się narzędziem front-end; dotarł do punktu, w którym wielu programistów napisze zdecydowaną większość swojego HTML w środku .Pliki js w postaci JSX.
w miarę jak język nabiera coraz większej roli, pomocne jest upewnienie się, że jedna z naszych najważniejszych struktur danych jest taka, jakiej oczekiwaliśmy. JavaScript może mieć słowo kluczoweclass
, ale w rzeczywistości jest to po prostu niezauważona funkcja konstruktora, a raz wywołana jest po prostu obiektem. Przedmioty są wszechobecne, dlatego czasami korzystne jest upewnienie się, że pasują do określonego kształtu.
ostatnio w pracy znalazłem przypadek, w którym deweloper oczekiwał, że właściwość zwrócona jako część odpowiedzi API będzie true
, ale zamiast tego otrzymał "true"
, powodując błąd. Łatwy błąd, którego można by uniknąć, gdybyśmy mieli interfejs.
ale czekaj, jest więcej!Interfejsy
, z kilkoma drobnymi modyfikacjami, mogą być używane do zmiany kształtu obiektów. Wyobraź sobie implementację” ścisłego ” interfejsu, w którym żadne właściwości poza interfejsem nie są dozwolone, możemy usunąć lub zmienić nazwy tych właściwości, a nawet wyrzucić błąd, jeśli je napotkamy.
więc teraz mamy interfejs, który powie nam, kiedy brakuje nam pewnych właściwości, ale także, gdy mamy nieoczekiwane właściwości lub jeśli typy właściwości nie są tym, czego oczekujemy. Dodaje to inne możliwości, na przykład refaktoryzację odpowiedzi z API, dodając dodatkową warstwę bezpieczeństwa na szczycie standardowego zachowania interfejsu. Możemy również użyć interfejsów w testach jednostkowych, jeśli mamy je wyrzucać błędy.
js
js jest biblioteką, która próbuje wprowadzić interfejsy do JavaScript. Pomysł jest prosty: zdefiniuj interfejs, określ typy jego właściwości i użyj go, aby upewnić się, że obiekt jest tym, czego oczekujesz.
Konfiguracja
najpierw zainstaluj pakiet:
npm install implement-js
następnie utwórz .plik js i import implement
Interface
I type
:
nasz pierwszy interfejs
aby utworzyć interfejs, po prostu zadzwoń do Interface
I podaj ciąg znaków jako nazwę interfejsu — nie jest to zalecane, ale jeśli pominiesz nazwę, wygenerowany zostanie unikalny identyfikator. Zwraca to funkcję, która akceptuje obiekt, w którym wszystkie właściwości są obiektami type
, drugi argument może być również przekazany z opcjami wyświetlania ostrzeżeń, wyrzucania błędów, usuwania lub zmiany nazwy właściwości, upewnienia się, że tylko właściwości interfejsu są obecne, lub rozszerzenia istniejącego Interface
.
oto interfejs opisujący samochód:
ma seats
właściwość, która powinna być typu number, tablica pasażerów, która zawiera obiekty, które same muszą implementować interfejs Passenger
I zawiera seats
beep
właściwość, która powinna być funkcją. Opcje error
I strict
zostały ustawione na true, co oznacza, że błędy będą generowane, gdy nie ma właściwości interfejsu, a także gdy właściwość nie znajduje się w interfejsie.
implementacja naszego interfejsu
teraz chcemy zaimplementować nasz interfejs, w prostym przykładzie stworzymy obiekt używając dosłownego obiektu i zobaczymy, czy jesteśmy w stanie zaimplementować nasz interfejs.
najpierw tworzymyFord
obiekt, następnie spróbujemy zaimplementować go w naszymCar
interfejs:
jak widzimy z powyższy komentarz powoduje błąd. Spójrzmy wstecz na naszCar
interfejs:
widzimy, że podczas gdy wszystkie właściwości są obecne, tryb ścisły jest również prawdziwy, co oznacza, że dodatkowa właściwośćfuelType
powoduje wyświetlenie błędu. Dodatkowo, mimo że posiadamy właściwośćpassengers
, nie jest to tablica.
aby poprawnie zaimplementować interfejs, usuwamy fuelType
I zmieniamy wartość passengers
tak, że jest to tablica zawierająca obiekty implementujące interfejs Passenger
:
„ale JavaScript nie jest językiem obiektowym!”
prawdą jest, że podczas gdy interfejsy są zwykle kojarzone z językami obiektowymi, a JavaScript jest językiem wieloparadygmatycznym, który wykorzystuje prototypowe dziedziczenie, interfejsy nadal mogą być bardzo przydatne.
na przykład, używając implement-js
możemy łatwo refaktorować odpowiedź API, zapewniając jednocześnie, że nie odbiegała od tego, czego oczekujemy. Oto przykład używany w połączeniu z redux-thunk
:
najpierw definiujemy interfejs TwitterUser
, który rozszerza interfejs User
, jako obiekt o twitterId
I twitterUsername
właściwości. trim
jest prawdziwe, co oznacza, że odrzucimy wszelkie właściwości nie opisane w interfejsie TwitterUser
. Ponieważ nasze API zwraca właściwości w nieprzyjaznym formacie, zmieniliśmy nazwę właściwości z twitter_username
I twitter_id
na same wersje camelcase.
następnie definiujemy akcję asynchroniczną za pomocąredux-thunk
, akcja wyzwala wywołanie API i używamy naszego interfejsuTwitterUser
, aby odrzucić właściwości, których nie chcemy i zapewnić, że implementuje właściwości, których oczekujemy, z poprawnymi typami. Jeśli wolisz zachować czystość swoich twórców akcji lub nie używaj redux-thunk
, możesz sprawdzić interfejs wewnątrz twitterService.getUser
I zwrócić wynik.
Uwaga: podczas rozszerzania opcji interfejsu nie są dziedziczone
testy jednostkowe są również odpowiednim miejscem do korzystania z interfejsów:
w podsumowaniu
widzieliśmy, jak interfejsy mogą być przydatne w JavaScript: mimo że jest to język bardzo dynamiczny, sprawdzenie kształtu obiektu i jego właściwości są specyficznym typem danych daje nam dodatkową warstwę bezpieczeństwa, której w przeciwnym razie byśmy nie zauważyli. Opierając się na koncepcji interfejsów i używając implement-js
, udało nam się również uzyskać dodatkowe narzędzie oprócz dodatkowego bezpieczeństwa.