TypeScript — pytania rekrutacyjne: typy a dane z API

TypeScript: pytania rekrutacyjne o dane z API. Zbuduj parser unknown, sprawdź unię statusów i odróżnij 4 błędy kompilatora od 31 kontroli wykonania.

Author: PracHub

Published: 10/11/2026

TypeScript — pytania rekrutacyjne: typy a dane z API

October 11, 2026

Quick Overview

Autorski kontrakt eksportu CSV: unknownJSON, statusy, runtimeparser, readonlyalias oraz rzeczywiste diagnostyki TypeScript i wyniki Node.

Software EngineerFree

Asercja as może przekonać kompilator, że odpowiedź API ma wymagany typ, bez sprawdzenia jej pól. Kompilator przestaje protestować, ale pole rows nadal zawiera tekst zamiast liczby. Na rozmowie rekrutacyjnej pokaż, gdzie kończy się wiedza systemu typów i jaki kod rzeczywiście sprawdza dane.

Prześledź autorski przykład usługi eksportującej plik CSV. Zadanie łączy unknown, zawężanie, unię dyskryminowaną i testy danych wejściowych. Jako następny krok wybierz Review and Improve Four AI-Assisted TypeScript Pull Requests, uzasadniając każdą obietnicę bezpieczeństwa konkretnym sprawdzeniem.

Granica dowodów: oficjalna dokumentacja TypeScript opisuje typy i ich zawężanie; kontrakt eksportu, parser i przypadki są autorskie. TypeScript 7.0.2 zaakceptował poprawne pliki i zgłosił cztery oczekiwane błędy w negatywnym przykładzie. W Node 26.9.0 przeszło 31 kontroli wykonania. Nie wywołano rzeczywistego API i nie pobrano pliku; nie używamy relacji kandydatów do twierdzeń o pytaniach konkretnej firmy.

Nieznany JSON musi przejść walidację przed utworzeniem wartości domenowej

Kontrakt eksportu przed deklaracją typu

Usługa zwraca zadanie o identyfikatorze takim jak exp-17. Dopuszczamy cztery statusy: queued, running, ready i failed. Każdy ma inny zestaw wymaganych pól. Ustalamy również, że nieznane pola są odrzucane. To świadoma polityka ćwiczenia, a nie konieczność wynikająca z TypeScript.

StatusPola poza id i statusReguła wykonania
queuedBrakNie przyjmujemy danych innych statusów
runningprogressSkończona liczba od 0 do 100 włącznie
readyrows, downloadUrlBezpieczna nieujemna liczba całkowita i dozwolony adres
failederrorCodeRETRY_LATER albo INVALID_QUERY

Postęp 100 nie oznacza automatycznie gotowego pliku; to status decyduje o dostępności pól. Gotowy eksport może zawierać zero wierszy. Nie stosuj warunku prawdziwości if (rows), bo odrzuciłby poprawne zero. Nie przekształcaj też tekstu "0" w liczbę bez uzgodnienia: ten kontrakt wymaga liczbowego pola JSON.

Identyfikator odpowiada wzorcowi exp- oraz dodatniej liczbie zapisanej bez zera wiodącego. Nie ustalono limitu długości identyfikatora ani rozmiaru całej odpowiedzi; implementacja nie udaje, że rozwiązuje ochronę przed nadmiernym wejściem. Te ograniczenia można dodać jako osobne wymagania.

Dlaczego asercja typu nie sprawdza JSON

Oficjalny rozdział Everyday Types opisuje asercje jako informację dla kompilatora, usuwaną podczas kompilacji. Zastosujmy ją do celowo błędnej odpowiedzi:

type Ready = { status: 'ready'; rows: number };
const raw: unknown = { status: 'ready', rows: '0' };
const job = raw as Ready;
const next = job.rows + 1;

Kompilator traktuje next jako liczbę, lecz wykonanie daje tekst "01". Kontrola assertion_no_runtime_validation zapisała dokładny wynik "01" dla docelowego wariantu eksportu. Asercja nie zmieniła wartości rows, nie sprawdziła formatu i nie utworzyła nowego obiektu. Uciszenie błędu nie jest dowodem poprawności odpowiedzi.

Nie naprawiaj tego kolejną asercją, na przykład as number. Najpierw sprawdź faktyczny typ pola w czasie wykonania. Jeśli usługa naprawdę dopuszcza liczby zapisane jako tekst, zaprojektuj jawny etap normalizacji i jego błędy. W naszym zadaniu taka odpowiedź jest odrzucana, aby rozbieżność kontraktu nie została ukryta przed dalszym kodem.

Unknown wyznacza miejsce wymagające dowodu

Wynik dekodowania zewnętrznego JSON przypisz do unknown, zanim użyjesz jego pól. unknown nie waliduje samodzielnie, ale wymaga zawężenia przed operacjami. W negatywnym pliku dostęp v.status dla v: unknown został odrzucony przez kompilator jako TS18046. Dzięki temu nie użyjesz statusu przed sprawdzeniem nieznanego wejścia.

Pierwsza kontrola odróżnia obiekt od null i tablicy:

function record(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object'
    && value !== null
    && !Array.isArray(value);
}

Sam warunek typeof value === 'object' nie wystarcza. Oficjalny rozdział o narrowing opisuje między innymi zachowanie null i analizę przepływu. Nasz predykat potwierdza tylko ogólny kształt kontenera; nie potwierdza jeszcze obecności identyfikatora, statusu ani pól konkretnego wariantu.

Po tej kontroli nadal traktuj wartości pól jako unknown. Nie przeskakuj od „to obiekt” do „to gotowy eksport”. Granica zaufania ma kilka kroków: kontener, identyfikator, dyskryminator i reguły jego pól. Każdy krok powinien uzasadniać dokładnie tę informację, którą potem wykorzystasz.

Unia opisuje dozwolone kombinacje pól

Jeden typ ze wszystkimi opcjonalnymi polami pozwalałby wyrazić wiele niepożądanych stanów. Rozdzielamy je według statusu:

type ExportJob =
  | Readonly<{ id: string; status: 'queued' }>
  | Readonly<{ id: string; status: 'running'; progress: number }>
  | Readonly<{
      id: string; status: 'ready';
      rows: number; downloadUrl: string;
    }>
  | Readonly<{
      id: string; status: 'failed';
      errorCode: 'RETRY_LATER' | 'INVALID_QUERY';
    }>;

Po sprawdzeniu job.status === 'ready' kod może korzystać z rows i downloadUrl. Nie musi używać ! do zapewniania kompilatora, że opcjonalne pole jednak istnieje. Wariant failed ma kod błędu, a nie przypadkowo pozostawiony adres pliku. Taki model pomaga również przygotować macierz przypadków parsera.

Typ nie zapewnia jednak, że liczba jest nieujemna albo adres należy do wybranego hosta. Zwykłe number i string są szersze niż reguły domenowe. Nie obiecuj, że unia automatycznie sprawdza te ograniczenia po odebraniu JSON. Typ końcowy opisuje wynik pracy parsera; odpowiedzialność za poprawność tej pracy nadal należy do implementacji.

Parser tworzy nową wartość po sprawdzeniu pól

Parser przyjmuje unknown, odrzuca błędny kontener i identyfikator, a następnie przechodzi przez switch statusu. Dla każdej gałęzi sprawdza dozwolone nazwy pól oraz ich wartości. Zwraca nowy obiekt zawierający wyłącznie zatwierdzone dane. Nie zwraca wejścia po zmianie jego typu w oczach kompilatora.

Dla rows warunek obejmuje typeof === 'number', Number.isSafeInteger oraz wartość co najmniej zero. W testach odrzucono tekst, liczbę ujemną, ułamek i liczbę poza bezpiecznym zakresem. Dla postępu dopuszczamy również ułamki, o ile liczba jest skończona i mieści się w 0–100. To dwie odrębne reguły; nie stosuj do obu przypadkowo tego samego walidatora.

Nieznane i sprzeczne pola są w ćwiczeniu błędem. Obiekt ready z dodatkowym errorCode zostaje odrzucony. Możliwa jest inna polityka, na przykład ignorowanie nowych pól dla zgodności kolejnych wersji API. Przed zmianą takiej decyzji określ, czy zależy ci na ścisłym wykrywaniu rozjazdu schematu, czy na tolerowaniu rozszerzeń. Wymaga to innych wyników testów.

Jak obronić dokładność walidatora

W gałęzi ready kontrola liczby wierszy jest krótka, ale każda część odpowiada innemu wymaganiu. Fragment poniżej pochodzi z wykonanego parsera; v jest już kontenerem sprawdzonym jako Record<string, unknown>. Nie jest to samodzielna funkcja przyjmująca dowolny obiekt.

if (typeof v.rows !== 'number'
    || !Number.isSafeInteger(v.rows)
    || v.rows < 0) {
  throw new TypeError('rows');
}

Usunięcie pierwszego warunku rozmywa zawężenie potrzebne kompilatorowi. Usunięcie kontroli całkowitości pozwoliłoby opisać pół wiersza; usunięcie dolnej granicy dopuściłoby liczbę ujemną. Przypadek poza bezpiecznym zakresem dotyczy wiarygodności reprezentacji liczby, a nie samej obecności pola. Zestaw negatywnych wejść powinien sprawdzać te ograniczenia oddzielnie, aby naprawa jednego nie zasłoniła utraty drugiego.

Zapytaj też o wersjonowanie kontraktu. Dodanie opcjonalnego pola przez serwer zostanie odrzucone przez naszą ścisłą listę dozwolonych nazw. To może być zamierzone podczas ćwiczenia wykrywania rozbieżności, lecz wymaga uzgodnienia w prawdziwej integracji. Nie usuwaj kontroli tylko dlatego, że jeden nowy przykład nie przechodzi: najpierw ustal oczekiwaną politykę i zaktualizuj macierz. Wykonane testy potwierdzają aktualne odrzucanie dodatkowego pola, nie zgodność z przyszłą wersją API.

Adres pliku: składnia i polityka to dwa sprawdzenia

Gotowy eksport wskazuje na https://files.example.test/exports/exp-17.csv. Domena .test jest elementem fikcyjnego przykładu; nie wykonujemy żądania. Parser używa konstruktora URL, a potem sprawdza protokół HTTPS, dokładny host i ścieżkę odpowiadającą identyfikatorowi. Odrzuca nieoczekiwany port, dane logowania, query oraz fragment.

Oficjalna dokumentacja konstruktora URL w MDN opisuje parsowanie i błąd nieprawidłowego adresu. Samo poprawne utworzenie URL nie oznacza, że aplikacja powinna otworzyć ten adres. Reguła hosta i ścieżki pochodzi z naszego kontraktu, a nie z konstruktora ani systemu typów.

Sprawdzono między innymi zmianę HTTPS na HTTP, obcy host i adres z nazwą użytkownika oraz hasłem. Nie przeprowadzono pełnego audytu bezpieczeństwa adresów, przekierowań, DNS czy pobierania plików. Jeśli usługa miałaby pobierać wskazany zasób po stronie serwera, potrzebowałaby dodatkowych zabezpieczeń. Walidacja przykładowej odpowiedzi nie zastępuje projektu takiego mechanizmu.

Predykat typu także może kłamać

Funkcja z deklaracją value is SomeType jest obietnicą programisty. Kompilator wykorzystuje ją do zawężenia, ale nie udowadnia, że każdy true wynika z kompletnych kontroli. W laboratorium celowo nieuczciwy predykat zawsze zwraca true dla typu z polem name: string.

Dla pustego obiektu kompilator dopuszcza późniejsze value.name.trim(), a wykonanie kończy się TypeError. Test odtwarza ten błąd i potwierdza jego przechwycenie. To przypomnienie, że elegancka sygnatura guarda nie jest walidatorem sama w sobie. Jego implementacja powinna sprawdzać to, co obiecuje, również na wejściach negatywnych.

Nasz predykat record obiecuje tylko kontener, a parser sprawdza resztę. W większym systemie możesz użyć biblioteki schematów, ale pokaż, jakie reguły faktycznie zapisano i jaki typ wyprowadzono. Nie deklaruj przewagi wydajności lub bezpieczeństwa biblioteki bez odpowiednich pomiarów i analizy. W tym ćwiczeniu parser jest ręczny, by jego decyzje były widoczne.

Readonly nie zamraża obiektu w wykonaniu

Oficjalny rozdział Object Types rozróżnia ograniczenia typów od mutowalności przez inne odwołania. Negatywny przykład bezpośredniego przypisania do pola readonly daje TS2540. To ochrona przy pisaniu kodu korzystającego z danego typu.

Osobny test tworzy mutowalny obiekt {rows: 0}, przypisuje go do odwołania Readonly<{rows: number}>, a następnie zmienia oryginał na jeden. Odczyt przez odwołanie readonly również daje jeden. Nie użyto zamrażania w czasie wykonania; oba odwołania wskazują ten sam obiekt. Ochrona zapisu przez jedno odwołanie nie usuwa pozostałych.

Parser ogranicza jeden problem przez utworzenie nowego obiektu. Po sparsowaniu poprawnego eksportu zmiana wejściowego rows na 99 nie zmienia wyniku z zerem. Wszystkie zwracane pola tego modelu są prymitywami. Test dotyczy nowego obiektu z polami prymitywnymi; nie dowodzi niezmienności zagnieżdżonych danych w wykonaniu: Readonly nie wykonało Object.freeze.

Kompilator i wykonanie: cztery oczekiwane diagnostyki oraz 31 sprawdzonych zachowań

Wyczerpująca obsługa działa po granicy walidacji

Po walidacji funkcja etykiety używa switch po czterech statusach. W gałęzi domyślnej przypisuje pozostałą wartość do never. Gdy w negatywnym pliku dodamy wariant paused bez jego obsługi, kompilator zgłasza błąd TS2322. To sygnał, że kod zależny od zamkniętej unii wymaga aktualizacji.

Taki test nie odrzuca sam nowych statusów z serwera. Robi to parser w swojej gałęzi błędu. Wyczerpujący switch i walidacja wejścia rozwiązują inne problemy: pierwszy pilnuje spójności kodu względem znanego modelu, druga sprawdza, czy nieznane dane wolno do niego wprowadzić. Wywołanie etykiety po samej asercji omija sprawdzenie, które miało chronić ją przed nieznanym statusem.

Test gotowego eksportu z zerem zwraca etykietę 0 wierszy. Dzięki temu poprawna pusta odpowiedź nie znika w gałęzi błędu ani oczekiwania. Jest to konkretny przypadek pokazujący korzyść z jawnego dyskryminatora i właściwej walidacji, zamiast serii warunków sprawdzających przypadkową obecność danych.

Co potwierdzają dwa zestawy sprawdzeń

Poprawny parser i testy skompilowano w trybie strict, z celem ES2022. Cztery celowe błędy dotyczą dostępu do unknown, tekstu w polu liczbowym, zapisu do readonly i pominiętego wariantu unii. Negatywny plik powinien zakończyć sprawdzanie niepowodzeniem; zielony wynik tego etapu oznaczałby, że eksperyment stracił znaczenie.

Wykonanie obejmuje 26 przypadków wejścia: siedem zaakceptowanych i dziewiętnaście odrzuconych. Pięć dodatkowych kontroli pokazuje lukę asercji, mutację przez alias readonly, odseparowanie wyniku parsera, etykietę zerowej liczby wierszy oraz nieuczciwy guard. Raport JSON zapisuje 31 kontroli lokalnego programu; nie jest dowodem działania usługi eksportu. NaN testowano dodatkowo jako wartość JavaScript; nie jest prawidłową liczbą w tekście JSON.

Nie sprawdzono uwierzytelnienia, uprawnień użytkownika do eksportu, poprawności zawartości CSV ani zgodności stanu z bazą. Poprawny kształt ready nie dowodzi, że osoba wywołująca ma prawo pobrać plik. W rozmowie nazwij te odrębne warstwy, zamiast obiecywać bezpieczeństwo całego API na podstawie parsera.

Pięć pytań PracHub do obrony granicy danych

Zweryfikowane pytania zachowują pełne angielskie tytuły. Rozwijają przegląd kodu, kontrakty API i przepływ typowanych danych; nie są prezentowane jako dedykowana polska kolekcja tego parsera.

Pytanie PracHubZwiązek z zadaniem eksportu
Review and Improve Four AI-Assisted TypeScript Pull RequestsWskaż twierdzenie typu bez pokrycia w wykonaniu
Design a REST API Abstraction LayerUmieść walidację i błędy na granicy odpowiedzi
Implement a Publish-Subscribe Event Bus in JavaScript or TypeScriptRozdziel typowany kontrakt od nieznanego źródła danych
Implement React logic with TypeScript hooksModeluj warianty stanu zamiast niepowiązanych pól opcjonalnych
Implement paginated, sortable dynamic table componentNie wpuszczaj błędnych danych API do renderowania

Wróć do Review and Improve Four AI-Assisted TypeScript Pull Requests. Dla każdej asercji zapytaj, skąd pochodzi wiedza o wartości, a dla każdego guarda przygotuj wejście, które powinien odrzucić. Dobra odpowiedź wskazuje zarówno gwarancję, jak i kod oraz test, które ją uzasadniają.

Sources and Further Reading


Comments (0)