Snelle vraag: hoe weet je dat je frontend en backend het eens zijn over hoe een "user" eruitziet?
Is het antwoord "we houden ze handmatig in sync"? Dan ken je de pijn. Iemand hernoemt een veld op de backend. De frontend weet van niks. Niks breekt tijdens het bouwen. Alles breekt om 2 uur 's nachts als echte gebruikers lege schermen zien.
Er is een betere aanpak. Je definieert de shape een keer. Al het andere wordt gegenereerd.
De pipeline
Pydantic Schema (Backend)
↓ FastAPI genereert automatisch
OpenAPI Specification (JSON)
↓ openapi-typescript
TypeScript Types (Frontend) Je schrijft het Pydantic-schema. FastAPI maakt er automatisch een OpenAPI-spec van. Een npm-script zet die spec om naar TypeScript types. Verander je een veld op de backend? De TypeScript-compiler vertelt je precies welke componenten moeten meeveranderen. Voor je pusht. Voor het productie bereikt.
Stap 1: definieer je schema met constraints
class TaskCreate(BaseModel):
project_id: UUID
assignee_id: UUID
due_date: datetime
story_points: int = Field(default=3, ge=1, le=21)
priority: TaskPriority # Enum
description: str = Field(..., min_length=3, max_length=500) Let op de constraints: ge=1, le=21, min_length=3. Die worden onderdeel van je API-spec. Frontend-validatie kent de regels. Zonder dat je ze dubbel schrijft.
Stap 2: koppel het aan FastAPI
@router.post("/", response_model=TaskResponse, status_code=201)
async def create_task(data: TaskCreate):
... Stap 3: genereer TypeScript types (een commando)
npx openapi-typescript http://localhost:8000/openapi.json -o src/types/api.ts Stap 4: gebruik ze overal
// TypeScript kent nu elke geldige task-status
const statusColors: Record<TaskStatus, string> = {
open: "blue",
in_progress: "green",
// Nieuwe status toevoegen? De compiler eist dat je het hier afhandelt.
}; Zes maanden resultaten
| Metriek | Resultaat |
|---|---|
| Compile-time fouten gevangen | 847 |
| Runtime type-fouten in productie | 0 |
| Snelheidsverbetering bij migraties | 57% sneller |
| Verbetering AI-generatienauwkeurigheid | +30% |
Valkuilen om te vermijden
- De
anynooduitgang: verbied het. ESLint'sno-explicit-any: "error". Elkeanyis een gat in je vangnet. - Handmatige type-duplicatie: schrijf je handmatig een TypeScript-interface die een backend-model spiegelt? Dan maak je een kans op drift. Alle API-types horen uit gegenereerde types te komen.
- Strict mode overslaan: zet
strict: trueaan in tsconfig.json. Strict mode vangt de bugs die permissive mode gewoon doorlaat.
Voeg het toe aan je CI
# In je CI-pipeline:
- Start backend (voor OpenAPI-spec)
- Run: openapi-typescript → genereert types
- Check: git diff --exit-code src/types/ # Fail als types gewijzigd maar niet gecommit
- Run: tsc --noEmit # Volledige type check Geen type drift komt hier langs. Wijzigt de backend een schema en zijn de frontend-types niet opnieuw gegenereerd? CI vangt het voor de merge.