API-Antworten in TypeScript typisieren

fetch liefert Daten mit dem Typ any, und damit schaltet sich TypeScript genau dort ab, wo Fehler entstehen. So geben Sie API-Daten schnell und sicher einen echten Typ.

Direkt ausprobieren: JSON to TypeScript JSON zu Typen

TypeScript prüft Ihren Code, aber keine Daten, die erst zur Laufzeit ankommen. Sobald Sie await response.json() aufrufen, erhalten Sie einen Wert vom Typ any, und von da an lässt Sie der Compiler user.adress.city mit Tippfehler lesen, ohne sich zu beschweren. Wer API-Antworten typisiert, schließt diese Lücke. Dieser Ratgeber zeigt, wie Sie die Typen schnell aus einem Beispiel gewinnen, wie Sie die kniffligen Stellen abbilden und wann ein Typ allein nicht genügt.

Schritt 1: die Typen aus einem echten Beispiel gewinnen

Interfaces für eine große Antwort von Hand zu schreiben ist langsam und fehleranfällig. Kopieren Sie stattdessen eine echte Antwort, etwa aus dem Tab Netzwerk der Entwicklertools im Browser oder aus der API-Dokumentation, und fügen Sie sie in JSON to TypeScript ein. Eine Antwort wie diese:

{
  "id": 1024,
  "name": "Ada",
  "tags": ["admin", "beta"],
  "address": { "city": "London", "zip": "N1 9GU" },
  "orders": [
    { "order_id": "A-17", "total": 42, "shipped_at": "2026-09-01T10:00:00Z" },
    { "order_id": "A-18", "total": 18.5, "shipped_at": null, "coupon": "WELCOME" }
  ]
}

wird, wenn Name des Wurzeltyps auf User steht, zu:

export interface Address {
  city: string;
  zip: string;
}

export interface Order {
  order_id: string;
  total: number;
  shipped_at: string | null;
  coupon?: string;
}

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

Achten Sie darauf, was der Generator aus den beiden Bestellungen abgeleitet hat: shipped_at war in einem Eintrag null, deshalb ist es string | null; coupon fehlte in einem Eintrag, deshalb ist es optional. Verschachtelte Objekte wurden zu eigenen, benannten Interfaces, und die Einträge von orders wurden zu Order. Alles läuft im Browser, eine Antwort mit echten Kundendaten wird also nirgendwohin gesendet.

Schritt 2: den Typ mit fetch verwenden

Am einfachsten verbinden Sie den Typ mit den Daten über eine kleine Hilfsfunktion:

async function getJson<T>(url: string): Promise<T> {
  const res = await fetch(url);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return (await res.json()) as T;
}

const user = await getJson<User>('/api/users/1024');
user.address.city;   // string, checked by the compiler

Das as T ist ein Versprechen, das Sie dem Compiler geben, keine Prüfung. Schickt der Server etwas anderes, bemerkt TypeScript das nicht. Für interne APIs, die Sie selbst kontrollieren, ist dieser Kompromiss oft in Ordnung; für alles andere lesen Sie weiter bei Schritt 4.

Schritt 3: die kniffligen Stellen abbilden

Im JSONIn TypeScriptWarum
Ein Schlüssel, der manchmal fehltcoupon?: stringOptional: Die Eigenschaft existiert unter Umständen nicht
Ein Wert, der manchmal null istshipped_at: string | nullNullable: Die Eigenschaft existiert, kann aber leer sein
Beidesnote?: string | nullDie API lässt sie womöglich weg oder schickt null
Ein DatumstringJSON hat keinen Datumstyp; bei Bedarf mit new Date() umwandeln
Eine große IDstring, wenn die API sie in Anführungszeichen schicktZahlen über 2^53 verlieren in JavaScript an Genauigkeit
Ein leeres Array im Beispielunknown[]Das Beispiel zeigt nicht, wie die Einträge aussehen

Ziehen Sie unknown dem Typ any für alles vor, was das Beispiel nicht verrät: unknown erzwingt eine Prüfung vor der Verwendung, während any die Prüfung stillschweigend abschaltet. Ein erzeugter Typ ist nur so vollständig wie sein Beispiel. Verwenden Sie deshalb eine Antwort, die auch die optionalen Felder enthält, oder ein Array mit mehreren unterschiedlichen Einträgen.

Schritt 4: zur Laufzeit prüfen, wenn die Daten nicht von Ihnen stammen

APIs von Drittanbietern ändern sich, Proxys liefern HTML-Fehlerseiten zurück, und alte Clients treffen auf neue Server. Eine Prüfung zur Laufzeit fängt solche Fälle an der Grenze ab, mit einer klaren Fehlermeldung, statt irgendwo tief in der Benutzeroberfläche. Zwei verbreitete Ansätze:

  • JSON Schema: Erzeugen Sie aus demselben Beispiel mit dem JSON Schema Generator ein Schema und prüfen Sie mit einer Bibliothek wie Ajv. Das Schema ist sprachunabhängig, ein Backend in einer anderen Sprache kann also dieselbe Datei verwenden.
  • Ein TypeScript-zentrierter Validator: Mit Bibliotheken wie Zod beschreiben Sie die Struktur einmal und leiten den TypeScript-Typ daraus ab, sodass Typ und Prüfung nie auseinanderlaufen können.

In beiden Fällen gilt: einmal prüfen, dort, wo die Daten in Ihr Programm kommen, und der übrige Code verlässt sich auf den Typ.

Wenn sich die API ändert

Einmal erzeugte Typen veralten, während die API wächst. Legen Sie das Beispiel, aus dem Sie die Typen erzeugt haben, neben den Typen im Repository ab, damit die nächste Person sie neu erzeugen und in einem Diff sehen kann, was sich geändert hat. Veröffentlicht die API eine OpenAPI-Beschreibung, ist es zuverlässiger, die Typen daraus zu erzeugen als aus Beispielen, weil sie jedes optionale Feld und jeden möglichen Wert auflistet, auch die, die eine einzelne Antwort nie zeigt. Bei APIs ohne eine solche Beschreibung macht ein Laufzeit-Validator aus Schritt 4 aus einer stillen Abweichung einen Fehler, den Sie in den Logs sehen.

interface oder type?

Für API-Daten funktioniert beides. Interfaces lassen sich erweitern und werden zusammengeführt, wenn sie zweimal deklariert werden, was manche Teams für öffentliche Typen schätzen; Typ-Aliase können zusätzlich Unions und Mapped Types ausdrücken. Entscheiden Sie sich im Projekt für einen Stil und bleiben Sie dabei. Der Generator erzeugt beides.

Andere Sprachen aus demselben Beispiel

Dasselbe JSON-Beispiel kann in JSON zu Typen auch zu Go-Structs, Pydantic-Modellen oder C#-Klassen werden; so bleiben Frontend und Backend bei derselben Struktur. Ist das Beispiel selbst fehlerhaft, zeigt der JSON Formatter, wo.

Häufige Fragen

Wie erzeuge ich TypeScript-Typen aus JSON?

Fügen Sie ein echtes Beispiel des JSON in einen Konverter von JSON zu TypeScript ein. Er erstellt Interfaces für jedes Objekt und erkennt optionale und nullable Felder anhand des Beispiels.

Warum ist res.json() als any typisiert?

Weil TypeScript zur Kompilierzeit nicht wissen kann, was ein Server schicken wird. Den Typ geben Sie dem Ergebnis selbst, mit einer generischen Hilfsfunktion oder einem Validator.

Prüft ein TypeScript-Typ die Daten?

Nein. Typen werden beim Kompilieren entfernt. Um Daten zur Laufzeit zu prüfen, verwenden Sie einen JSON-Schema-Validator oder eine Bibliothek wie Zod.

Soll ich optional oder null verwenden?

Richten Sie sich nach der API: ein Fragezeichen, wenn der Schlüssel fehlen kann, und eine Union mit null, wenn der Schlüssel mit dem Wert null vorhanden ist.

Wie sollten Datumsangaben in JSON typisiert werden?

Als string, denn JSON hat keinen Datumstyp. Wandeln Sie sie in Date-Objekte um, wo Sie mit Daten rechnen müssen.
Direkt ausprobieren: JSON to TypeScript JSON zu Typen