§

Próbka JSON

Przygotowywanie wnioskowania typów…
§

Interfejsy TypeScript

TypeScript

Polskie zespoły TypeScript napotykają ten problem wcześnie. Duże SDK dostarczają typowanych klientów (Stripe, Twilio, AWS), ale wewnętrzne usługi i payloady webhooków firm trzecich rzadko to robią — typowy przepływ pracy to: przechwycenie prawdziwej odpowiedzi w panelu sieci, wklejenie tutaj, nazwanie roota po endpoincie i skopiowanie wyniku do katalogu types projektu. Stamtąd strict mode łapie rozbieżności, o których dokumentacja zapomniała wspomnieć. Wnioskowanie działa całkowicie w przeglądarce, więc payloady z API stagingowych, podpisane ciała webhooków i nieudostępnione endpointy nigdy nie trafiają do hostowanej usługi.

Jak działa wnioskowanie JSON do TypeScript?

Wnioskowanie to pojedynczy przebieg przez przetworzone drzewo JSON. Narzędzie odczytuje każdą wartość, wybiera dla niej typ TypeScript, a następnie zapisuje jeden interfejs na każdy znaleziony obiekt.

  1. Parsuj próbkę JSON natywnym parserem przeglądarki i odrzucaj zniekształcone dane wejściowe z podpowiedzią wiersza/kolumny.
  2. Wykryj typ TypeScript dla każdej wartości — string, number, boolean, null, tablica lub zagnieżdżony obiekt.
  3. Nadaj każdemu zagnieżdżonemu obiektowi nazwę interfejsu wywodzoną z klucza właściwości rodzica (więc user.address staje się interfejsem Address).
  4. Scalaj typy elementów po każdej tablicy, by lista {id: 1} i {id: 2, label: "x"} produkowała unię z właściwymi opcjonalnymi polami.
  5. Zastosuj opcje (interface vs. type, readonly, opcjonalny-nullable) i emituj deklaracje w kolejności zależności, by plik kompilował się bez odwołań do przyszłości.

Dlaczego generować typy TypeScript z JSON?

  • Większość błędów kształtu jest łapalna w czasie kompilacji, jeśli typ odpowiedzi jest zapisany. Wywnioskowanie interfejsu z prawdziwego payloadu zapisuje większość za Ciebie, a tryb `strict` łapie pole, o którym dokumentacja zapomniała wspomnieć.
  • Parowanie wywnioskowanych interfejsów z walidatorem runtime jak Zod lub io-ts daje temu samemu kształtowi dwie prace: autouzupełnianie edytora podczas deweloperki i błąd 400 na krawędzi gdy produkcja wyśle coś nieoczekiwanego.
  • Serwer językowy TypeScript pokazuje tylko pola, o których wie. Gdy zaimportujesz wywnioskowany interfejs, autouzupełnianie działa w momencie wpisania kropki — koniec z rzutowaniem `as any` na odpowiedź i sfrustrowanym grepowaniem po repozytorium.
  • Jeśli zamierzasz napisać specyfikację OpenAPI, wywnioskowany interfejs to szybki pierwsza wersja robocza schematu odpowiedzi. Nadal będziesz chciał ręcznie pisane przykłady i ograniczenia, ale nazwy właściwości i typy są już poprawne.

Typowe zastosowania

Wnioskowanie pomaga najbardziej gdy prawdziwy payload istnieje, ale schemat nie.

  • Typowanie webhooków firm trzecich od Stripe, GitHub lub Twilio przed napisaniem handlera.
  • Bootstrapowanie typów dla wewnętrznego API REST, by zespół front-endu mógł zacząć kodować względem niego tego samego dnia gdy backend wyląduje.
  • Generowanie punktu startowego dla schematu Zod, io-ts lub Valibot z obserwowanej odpowiedzi API.

Jak wygląda wynik?

Dla przykładowego dokumentu JSON i nazwy roota generator produkuje drzewo interfejsów, jeden na zagnieżdżony obiekt. Dla poniższego wejścia z nazwą roota User:

Wklej {"id":1,"name":"Alice","tags":["a","b"],"address":{"city":"Paris"}} z nazwą roota User a generator produkuje:

export interface User {
  id: number;
  name: string;
  tags: string[];
  address: Address;
}

export interface Address {
  city: string;
}
Zauważ, że address zostało awansowane do własnego nazwanego interfejsu — to wynik w kolejności zależności. Ten sam JSON ze stylem deklaracji type zamiast emitowałby export type User = {...}; z włączonym przełącznikiem readonly każda właściwość dostaje modyfikator readonly.

Opcje generatora

Styl deklaracji

Wybierz interface (standardowy idiom TypeScript dla kształtów obiektów) lub type (przydatny gdy będziesz potrzebować typów mapowanych, warunkowych lub przecięć później). Oba produkują identyczne zachowanie runtime; wybór to preferencja stylu kodowania.

Opcjonalne pola dopuszczające null

Gdy próbkowana wartość to null, typ pola staje się T | null. Włączenie tej opcji dodaje też modyfikator ?, więc pole jest opcjonalne po stronie TypeScript — przydatne gdy API czasem całkowicie pomija klucz zamiast zwracać null.

Modyfikator readonly

Dołącza readonly do każdej deklaracji właściwości, by emitowany interfejs pasował do niezmiennego modelu danych. Przydatne dla wycinków stanu Redux, zamrożonych odpowiedzi API lub wszędzie gdzie chcesz, by kompilator flagował przypadkowe mutacje.

Czy obsługuje zagnieżdżone obiekty i tablice?

Tak. Każdy zagnieżdżony obiekt staje się nazwanym interfejsem wywiedzionym z klucza właściwości rodzica, a tablice wnioskują typ elementu ze swojej zawartości. Tablice obiektów dostają interfejs na kształt obiektu, z typami unii tam gdzie kształty się różnią.

Jak są wnioskowane opcjonalne pola?

Włącz przełącznik "Oznacz pola dopuszczające null jako opcjonalne" a każde pole, którego próbkowana wartość to null, dostaje modyfikator ? na kluczu plus | null w typie. Bez przełącznika pole pozostaje wymagane a typ to tylko T | null.

Czy obsługuje dyskryminowane unie?

Podstawowe typy unii wychodzą gdy tablica zawiera elementy o mieszanych kształtach lub gdy pole niesie zarówno wartość jak i null. Pełne wnioskowanie dyskryminowanych unii (wybieranie type lub kind jako tagu i dzielenie wariantów) wymaga wielu próbek — jest zaplanowane, ale nie w dzisiejszej wersji.

Czy mogę wnioskować typy z wielu próbek JSON?

Jeszcze nie — dzisiejsze wnioskowanie czyta jedną próbkę na raz. Jeśli masz dwa payloady które powinny dzielić interfejs (powiedzmy endpoint listy i endpoint pojedynczego elementu), praktycznym obejściem jest scalenie ich w jedną tablicę, wygenerowanie z tego i zmiana nazw wynikowych typów unii. Wnioskowanie z wielu próbek jest na mapie drogowej, bo to jedyny sposób na wykrycie pól obecnych w jednej odpowiedzi a nieobecnych w innej.

Wklej payload, nazwij root, skopiuj interfejsy. Cały potok działa w przeglądarce, więc nieudostępniony API lub podpisane ciało webhooka zostaje na Twoim komputerze.