Zaczynasz agenta AI od pięćdziesięciu linii JavaScript. Działa. Integracja z API Claude'a gotowa w jeden wieczór, kilka promptów, pierwsze wyniki. Trzy miesiące później: czterdzieści plików, pięć osób w teamie, nikt nie pamięta, jaki kształt ma odpowiedź z API. Funkcja parsująca wyniki trzyma się na "mniej więcej wiem, co tu przychodzi". Błędy ujawniają się na produkcji, nie w edytorze.
To nie jest historia o złym kodzie. To historia o tym, że JavaScript był świetny na start — ale nie skaluje się do złożonych systemów AI bez dodatkowej warstwy bezpieczeństwa. Tą warstwą jest TypeScript.
Typy przy pracy z LLM API
Claude, GPT-4, Gemini — każde z tych API zwraca złożony, zagnieżdżony JSON. Wiadomość ma pole content, które jest tablicą bloków, każdy blok ma typ i dane zależne od tego typu, tool_use ma inne pola niż text, stop_reason może być jedną z kilku wartości enum. Bez typów programujesz "na pamięć" i liczyć na to, że API nie zmieni struktury odpowiedzi.
Przykład z SDK Anthropica w TypeScript:
```typescript import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();
type ToolSchema = {
name: string;
description: string;
input_schema: {
type: 'object';
properties: Record
async function callAgent(userMessage: string, tools: ToolSchema[]) { const response = await client.messages.create({ model: 'claude-opus-4-5', max_tokens: 1024, tools, messages: [{ role: 'user', content: userMessage }], });
// TypeScript wie, że response.content to ContentBlock[] // i że każdy blok ma pole type const toolUse = response.content.find(block => block.type === 'tool_use'); if (toolUse && toolUse.type === 'tool_use') { // Tutaj TypeScript wie, że toolUse.name i toolUse.input istnieją console.log(toolUse.name, toolUse.input); } } ```
Bez typów ten kod wygląda podobnie, ale różnica pojawia się przy refaktoryzacji lub zmianie SDK — kompilator natychmiast wskazuje, co się zepsuło. W JavaScript dowiesz się o błędzie w runtime, zwykle na produkcji.
Zod + TypeScript = bezpieczeństwo na brzegu systemu
TypeScript działa w czasie kompilacji — chroni Cię przed błędami, które sam piszesz. Ale LLM potrafi zwrócić coś nieoczekiwanego: inny format daty, pole JSON z inną nazwą niż zadeklarowana, zagnieżdżoną strukturę zamiast płaskiej. TypeScript tego nie złapie, bo nie ma jak zweryfikować danych w runtime.
Tu wchodzi Zod. Używasz go na granicach systemu — wszędzie, gdzie dane przychodzą z zewnątrz: odpowiedź LLM, żądanie API, wynik tool call.
```typescript import { z } from 'zod';
const AgentResultSchema = z.object({ action: z.enum(['search', 'summarize', 'reply']), payload: z.string(), confidence: z.number().min(0).max(1), });
type AgentResult = z.infer
function parseAgentOutput(raw: unknown): AgentResult { return AgentResultSchema.parse(raw); // Rzuca ZodError jeśli LLM zwrócił coś innego niż schemat } ```
Połączenie Zod i TypeScript daje pełne pokrycie: błędy logiczne łapiesz w edytorze, błędy danych łapiesz przy wejściu do systemu. Halucynowany JSON przestaje docierać do reszty kodu.
W MKM Labs to standardowe podejście w każdym projekcie AI — Zod przy parsowaniu odpowiedzi LLM, TypeScript przez cały pozostały kod.
Refaktoryzacja bez strachu
Wyobraź sobie, że decydujesz się zmienić model z GPT-4 na Claude 3.5 Sonnet — albo że restrukturyzujesz przepływ promptów, bo jeden wielki łańcuch rozbijasz na wyspecjalizowane agenty. W JavaScript: zmieniasz kod, uruchamiasz, czekasz na błędy w runtime. Część błędów znajdziesz od razu, część po tygodniu, gdy konkretna ścieżka zostanie wywołana.
W TypeScript kompilator przechodzi przez cały projekt i mówi Ci dokładnie, co się zepsuło. Zmieniłeś kształt obiektu przekazywanego między agentami? Kompilator pokaże każde miejsce, które zakłada stary kształt. Zmieniłeś nazwę pola w schemacie tool call? Wskaże każde użycie starej nazwy.
Refaktoryzacja z TypeScriptem to dialog z kompilatorem: "co jeszcze muszę naprawić?" zamiast "czy coś się jeszcze nie zepsuło?". Przy projekcie z dziesiątkami plików ta różnica mierzy się w godzinach zaoszczędzonego debugowania na każdej większej zmianie.
Praktyczne porady dla małych projektów
Kilka zasad, które stosujemy przy każdym nowym projekcie AI:
Zacznij od strict: true w tsconfig.json. Tryb ścisły wymusza dokładne typowanie i blokuje najczęstsze pułapki — niejawne any, niesprawdzone null, niekompletne switch. Lepiej zacząć ze strict od pierwszego commita niż naprawiać setki błędów po miesiącu.
Typuj schematy narzędzi jako pierwsze. Tool schema to kontrakt między Twoim kodem a LLM. Jeśli jest wpisany na twardo jako string lub object, każda zmiana schematu wymaga ręcznego przeszukiwania kodu. Z typem — kompilator zrobi to za Ciebie.
Używaj as const dla szablonów promptów. Stałe tablice z możliwymi wartościami (role agenta, dostępne narzędzia, tryby pracy) powinny być literalnymi typami, nie luźnymi stringami. as const zamraża wartość i pozwala TypeScriptowi na precyzyjne typowanie.
Preferuj unknown nad any. Kiedy nie wiesz, co przychodzi z API — użyj unknown zamiast any. unknown wymusza sprawdzenie przed użyciem, any wyłącza sprawdzanie całkowicie. To drobna zmiana w pisaniu, ale ogromna przy debugowaniu.
Zawęź typy jak najwcześniej. Jeśli funkcja dostaje odpowiedź z LLM, sprawdź jej typ na wejściu i operuj już na zawężonym typie. Im wcześniej system "wie", z czym ma do czynienia, tym mniej place'holderów i as castów pojawi się w głębi kodu.
Jak zacząć jeśli masz projekt w JS
Jeśli masz działający projekt w JavaScript i chcesz przejść na TypeScript — dobra wiadomość: nie musisz robić tego naraz.
Pierwszy krok to tsc --init w głównym katalogu projektu. Plik tsconfig.json pojawi się z rozsądnymi domyślnymi. Ustaw strict: true i allowJs: true — to pozwoli na stopniowe dodawanie plików TS obok istniejących JS.
Zamiast od razu zmieniać rozszerzenia plików, możesz zacząć od @ts-check w komentarzu na górze pliku JS:
```javascript // @ts-check
/**
* @param {string} prompt
* @param {{ name: string; description: string }[]} tools
* @returns {Promise
To pozwala korzystać z typowania bez zmiany rozszerzenia. Potem, gdy jesteś gotowy, zmieniasz plik na .ts i usuwasz JSDoc — typy trafiają do sygnatur funkcji.
Przy małym projekcie (kilkanaście plików) migracja zajmuje jeden do dwóch dni. Przy większym — warto migrować moduł po module, zaczynając od tych, które zmieniają się najczęściej lub mają najwięcej błędów.
Podsumowanie
TypeScript przy budowaniu agentów AI to nie modny dodatek — to pragmatyczne narzędzie, które skraca czas debugowania, ułatwia pracę w teamie i pozwala bezpiecznie refaktoryzować rosnący system.
Typy przy odpowiedziach LLM, Zod na granicach systemu, strict mode od pierwszego commita — to nawyki, które MKM Labs stosuje domyślnie w każdym projekcie AI, od proof-of-concept przez MVP po produkcyjne wdrożenia.
Budujemy systemy AI z TypeScriptem od pierwszego commita. Porozmawiaj z nami o swoim projekcie.
Potrzebujesz podobnego rozwiązania?
Porozmawiajmy o Twoim projekcie
Pierwsza rozmowa jest bezpłatna. Opisz nam swój pomysł — odpowiemy w ciągu jednego dnia roboczego.
Umów bezpłatną rozmowę