Interfejsy w TypeScript: od składni do interface vs type
Interfejsy w TypeScript
Interfejs w TypeScript: składnia, extends, łączenie, a type | We.Inc
Zbuduj interfejs pole po polu, zobacz odpowiadający mu alias typu i poznaj pola opcjonalne i readonly, extends, łączenie deklaracji oraz sytuacje, w których alias typu sprawdza się lepiej.
Interfejs nadaje nazwę kształtowi obiektu: jakie ma właściwości i jakiego typu jest każda z nich. Oznacz właściwość jako opcjonalną przez ?, a jako niezmienną przez readonly, rozbuduj inny kształt przez extends i zadeklaruj ponownie tę samą nazwę, aby dołączyć kolejne pola. Interfejsy nie zostawiają śladu w skompilowanym JavaScripcie; służą wyłącznie kompilatorowi.
Składnia interfejsów w skrócie
Chcesz
Napisz
Właściwość wymaganą
name: string;
Właściwość opcjonalną
nickname?: string;
Właściwość, której nie można ponownie przypisać
readonly id: number;
Metodę
greet(other: User): string;
Dowolną liczbę kluczy tekstowych
[key: string]: number;
Ponownie użyć innego kształtu
interface Admin extends User { ... }
Połączyć kilka kształtów
interface A extends B, C { ... }
Dodaj pola w generatorze poniżej, zaznacz opcjonalne lub readonly i skopiuj interfejs albo równoważny alias typu. Sekcje niżej omawiają rozszerzanie, łączenie deklaracji i te nieliczne przypadki, w których wybór między interface a type naprawdę ma znaczenie.
Nazwij interfejs, a jeśli rozszerza inny, wpisz jego nazwę w polu extends.
Dodaj wiersz dla każdej właściwości, wybierając jej typ i to, czy jest opcjonalna lub readonly.
Przeczytaj interfejs i alias typu, które generator tworzy z tych samych wierszy.
Skopiuj dowolną wersję do swojego kodu.
Zaczynaj od interface dla kształtów obiektów, a po type sięgaj, gdy potrzebujesz unii, krotki lub typu mapowanego. Taką heurystykę proponuje sam podręcznik TypeScript.
readonly blokuje tylko ponowne przypisanie tej jednej właściwości. Obiekty zagnieżdżone w niej nadal mogą się zmieniać, a w czasie działania nic nie jest egzekwowane.
Właściwość opcjonalna przy odczycie ma swój typ lub undefined, więc sprawdź ją przed użyciem albo nadaj jej wartość domyślną przy destrukturyzacji.
Nazywaj interfejsy w liczbie pojedynczej i opisowo, na przykład Invoice lub CartItem. Przedrostek w stylu IInvoice nie dodaje niczego, czego edytor już Ci nie mówi.
Najczęściej zadawane pytania
Używać interface czy type?
Dla kształtów obiektów działa jedno i drugie, a podręcznik nazywa to głównie kwestią osobistych preferencji i sugeruje interface, dopóki nie potrzebujesz funkcji dostępnej tylko w type. Używaj type dla unii, krotek, typów prostych oraz typów mapowanych i warunkowych; używaj interface, gdy chcesz łączenia deklaracji.
Czym jest łączenie deklaracji?
Zadeklarowanie interfejsu o nazwie, która już istnieje, dodaje do niego pola zamiast zgłaszać błąd. Biblioteki na tym polegają, abyś mógł rozszerzać ich typy, na przykład dodając właściwość do Window. Alias typu z powtórzoną nazwą to błąd.
Co się stanie, jeśli dwa łączone interfejsy nadają właściwości różne typy?
Kompilator zgłosi błąd. Przy przecięciu dwóch typów konflikt nie jest zgłaszany w miejscu deklaracji; właściwość staje się never, co wychodzi na jaw później i trudniej to wyśledzić.
Czy interfejs może opisywać funkcję lub tablicę?
Tak. Sygnatura wywołania, taka jak (value: string): boolean, opisuje funkcję, a sygnatura indeksu, taka jak [index: number]: string, opisuje obiekt podobny do tablicy. W prostych przypadkach alias typu, na przykład type Check = (v: string) => boolean, czyta się łatwiej.
Czy interfejsy istnieją w czasie działania?
Nie. Kompilują się do niczego, więc nie możesz użyć instanceof z interfejsem ani wypisać jego kluczy. Sprawdzaj wartości funkcją strażnikiem w czasie działania i oznacz jej typ zwracany interfejsem.
extends a przecięcia typów
interface Bear extends Animal kopiuje każde pole Animal i pozwala dodać kolejne. Alias typu robi to samo za pomocą przecięcia: type Bear = Animal & { honey: boolean }.
Podręcznik zauważa, że extends może być szybsze dla kompilatora i że zgłasza konflikty pól dokładnie tam, gdzie zostały zadeklarowane. Przecięcia przydają się do sklejania kształtów, które nie są Twoje.
Pola opcjonalne, readonly i sygnatury indeksu
Znak zapytania po nazwie sprawia, że właściwość jest opcjonalna, a jej typ przy odczycie obejmuje undefined. readonly blokuje przypisanie do tej właściwości po utworzeniu, ale to wyłącznie kontrola na etapie kompilacji.
Sygnatura indeksu, [key: string]: number, opisuje słowniki, których kluczy nie da się wymienić z góry. Nazwane właściwości w tym samym interfejsie muszą pasować do typu wartości sygnatury indeksu.
Łączenie deklaracji w celu rozszerzenia typów globalnych i bibliotecznych
Ponieważ interfejsy się łączą, plik deklaracji może dodać Twoje własne pola do wbudowanych kształtów. Częsty przypadek to nadanie obiektowi Window właściwości, którą ustawia skrypt, aby jej odczyt przechodził kontrolę typów bez rzutowania.
interface a alias typu
Co potrafi każda z deklaracji
Możliwość
alias typu
Opisanie kształtu obiektu
Tak
Tak
Dodawanie pól przez ponowną deklarację nazwy
Tak (łączenie)
Nie, błąd zduplikowanego identyfikatora
Rozbudowa innego kształtu
Przecięcie za pomocą &
Unia kształtów lub literałów
Nie
Tak
Nazwanie typu prostego lub krotki
Nie
Tak
Typy mapowane i warunkowe
Nie
Tak
Wzorce, które będziesz często pisać
Rozszerzanie jednego i kilku interfejsów
Admin dostaje wszystkie pola User oraz własne; Card łączy dwa niezwiązane kształty.
Łączenie deklaracji dla Window
Umieszczone w pliku .d.ts sprawia, że window.appVersion przechodzi kontrolę typów wszędzie.
Sygnatura indeksu i sygnatura wywołania
Scores przyjmuje dowolny klucz tekstowy; Validator opisuje wartość, którą można wywołać.
Generator interfejsów
Nazwa interfejsu
Extends (opcjonalnie)
Nazwa właściwości {n}
Typ właściwości {n}
Opcjonalna
Readonly
Usuń właściwość {n}
Dodaj właściwość
Jako interfejs
Jako alias typu
Kopiuj interfejs
Kopiuj typ
Nazwy muszą zaczynać się od litery, $ lub _ i zawierać tylko litery, cyfry, $ lub _.