TypeScript satisfies Operator: Typprüfung ohne Weitung
AI generated
type
TypeScript
Der satisfies Operator: Typprüfung ohne Typ-Weitung
Objektliterale präzise prüfen, ohne Literal-Informationen zu verlieren

Der mit TypeScript 4.9 eingeführte satisfies Operator schließt eine Lücke zwischen expliziten Typannotationen und as Type Assertions. Er prüft, ob ein Ausdruck zu einem Typ passt, behält dabei aber den konkreten, engeren Typ des Ausdrucks bei.

9 Min. Lesezeit TypeScript 4.9+ Compiler-Feature

1. Das Problem: Annotation oder Assertion

Vor TypeScript 4.9 gab es für die Prüfung eines Objektliterals gegen einen Typ nur zwei Werkzeuge, und beide hatten Nachteile. Eine explizite Typannotation wie const config: Config = { ... } prüft die Struktur zuverlässig, weitet aber jede Eigenschaft auf den deklarierten Typ auf. Ein Feld vom Typ string bleibt string, selbst wenn der tatsächliche Wert nur "json" oder "xml" sein kann.

Die Alternative war eine Type Assertion mit as. Diese behält zwar die engeren Literal-Typen bei, verzichtet aber komplett auf eine strukturelle Prüfung durch den Compiler. Tippfehler in Eigenschaftsnamen oder fehlende Pflichtfelder fallen so erst zur Laufzeit auf, wenn überhaupt.

Der satisfies Operator kombiniert beide Eigenschaften: Er validiert den Ausdruck gegen einen Typ und meldet Fehler bei fehlenden oder falschen Feldern, behält aber gleichzeitig den konkreten, abgeleiteten Typ des Ausdrucks bei, statt ihn auf den geprüften Typ zu weiten.

2. Grundlagen der Syntax

Die Syntax ist bewusst schlicht gehalten: Ein Ausdruck wird gefolgt vom Schlüsselwort satisfies und einem Typ. Der Compiler prüft die Kompatibilität, der resultierende Typ der Variable bleibt aber der ursprüngliche, engere Typ des Ausdrucks.

Im folgenden Beispiel wird ein Konfigurationsobjekt gegen ein Interface geprüft. Trotz der Prüfung bleibt der Typ von route das Literal "GET" und nicht der breitere Typ string.

Diese Reihenfolge, Ausdruck zuerst und Typ danach, unterscheidet satisfies bewusst von einer Typannotation, bei der der Typ vor dem Ausdruck steht. Der Compiler liest den Operator dadurch als nachträgliche Prüfung, nicht als vorab festgelegte Deklaration, was sich auf die Art der Typinferenz auswirkt.


interface RouteConfig {
  method: string;
  path: string;
  cache: boolean;
}

const route = {
  method: "GET",
  path: "/products",
  cache: true,
} satisfies RouteConfig;

// route.method hat den Typ "GET", nicht string
function handle(method: "GET" | "POST") {
  // ...
}

handle(route.method); // funktioniert, weil "GET" literal erhalten bleibt

3. Kombination mit as const

Besonders nützlich wird satisfies in Kombination mit as const. Während as const alle Eigenschaften auf ihre engstmöglichen, unveränderlichen Literal-Typen fixiert, sorgt satisfies zusätzlich für eine strukturelle Prüfung gegen ein erwartetes Interface.

Ohne satisfies müsste man bei einer reinen as const Deklaration auf eigene Faust sicherstellen, dass die Struktur zum erwarteten Schema passt. Mit satisfies bekommt man beides gleichzeitig: Validierung und maximale Typpräzision.


type Theme = {
  primary: string;
  secondary: string;
  radius: number;
};

const theme = {
  primary: "#0f172a",
  secondary: "#e11d48",
  radius: 8,
} as const satisfies Theme;

// theme.radius ist vom Typ 8, nicht number
// theme.primary ist vom Typ "#0f172a", nicht string

4. Verwendung mit Record und Union-Schlüsseln

Ein häufiger Anwendungsfall ist die Prüfung von Objekten mit einem festen Satz an Schlüsseln, etwa einer Zuordnung von Feature-Flags oder Routen. Mit einem Record-Typ als Prüfziel stellt satisfies sicher, dass alle erwarteten Schlüssel vorhanden sind, ohne die konkreten Werttypen zu verallgemeinern.

Das ist besonders wertvoll, wenn später mit den einzelnen Werten weitergearbeitet wird, etwa in einer switch-Anweisung, die auf konkrete Literale prüft.

Ohne satisfies müsste man entweder auf eine reine Typannotation zurückgreifen, die jeden Wert auf boolean verallgemeinert, oder eine as Assertion verwenden, die fehlende Schlüssel unbemerkt lässt. Erst die Kombination aus Record-Typ und satisfies liefert beides zugleich: vollständige Schlüsselprüfung und erhaltene Literal-Präzision der einzelnen Werte.


type Feature = "checkout" | "wishlist" | "reviews";

const featureFlags = {
  checkout: true,
  wishlist: false,
  reviews: true,
} satisfies Record<Feature, boolean>;

// Fehlt ein Schlüssel oder ist ein zusätzlicher vorhanden,
// meldet der Compiler sofort einen Fehler.

5. Konfigurationsobjekte und Funktionsrückgaben

In Anwendungen mit vielen Konfigurationsobjekten, etwa Routendefinitionen, API-Client-Optionen oder Theme-Einstellungen, zahlt sich satisfies besonders aus. Statt jedes Objekt mit einer eigenen Typannotation zu versehen, die Literal-Informationen verwirft, bleibt die volle Präzision erhalten, während Tippfehler weiterhin auffallen.

Auch bei Funktionen, die Konfigurationsobjekte zurückgeben, lässt sich satisfies direkt auf den Rückgabewert anwenden, sodass Aufrufer von den engeren Typen profitieren.


interface ApiOptions {
  baseUrl: string;
  timeout: number;
  retries: number;
}

function buildOptions() {
  return {
    baseUrl: "https://mironsoft.de/api",
    timeout: 5000,
    retries: 3,
  } satisfies ApiOptions;
}

const options = buildOptions();
// options.timeout ist vom Typ 5000

6. Verschachtelte Strukturen und Arrays

satisfies arbeitet nicht nur mit flachen Objekten, sondern auch mit verschachtelten Strukturen und Arrays von Objekten. Der Compiler prüft rekursiv jede Ebene gegen den angegebenen Typ, während die konkreten Literal-Typen jeder Ebene erhalten bleiben.

Das erlaubt zum Beispiel Arrays von Navigationseinträgen, bei denen jeder Eintrag weiterhin seinen exakten Pfad-String als Typ behält, was in Kombination mit Routing-Bibliotheken für zusätzliche Typsicherheit sorgt.


interface NavItem {
  label: string;
  href: string;
  external?: boolean;
}

const navigation = [
  { label: "Magento", href: "/magento" },
  { label: "Hyva", href: "/hyva" },
  { label: "Blog", href: "https://mironsoft.de/blog", external: true },
] satisfies NavItem[];

7. Vergleich zu as und expliziten Annotationen

Der entscheidende Unterschied zu as liegt in der Fehlerprüfung. Eine as Assertion sagt dem Compiler im Grunde, ihm zu vertrauen, ohne eine echte strukturelle Prüfung durchzuführen. Fehlt eine Pflichteigenschaft, meldet as keinen Fehler, satisfies dagegen schon.

Der Unterschied zur expliziten Typannotation liegt im resultierenden Typ. Eine Annotation wie const x: Config = {...} weitet die Eigenschaften auf die im Interface deklarierten Typen. satisfies dagegen leitet den Typ weiterhin vom Ausdruck selbst ab und nutzt das angegebene Interface nur zur Validierung.

In der Praxis bedeutet das: Wer sich für as entscheidet, verzichtet bewusst auf Sicherheit zugunsten von Kontrolle. Wer eine Typannotation wählt, verzichtet auf Präzision zugunsten von Einfachheit. satisfies verlangt keinen dieser Kompromisse und sollte deshalb in den meisten Fällen die erste Wahl sein.

8. Best Practices für den Einsatz

satisfies eignet sich besonders für Konfigurationsobjekte, Lookup-Tabellen, Theme-Definitionen und alles, bei dem später mit den exakten Literal-Werten weitergearbeitet wird. Für einfache Variablen ohne weitere Verwendung der Literal-Typen reicht oft weiterhin eine normale Annotation.

In Bibliothekscode, der von vielen Konsumenten genutzt wird, hilft satisfies dabei, öffentliche Konstanten so präzise wie möglich zu typisieren, ohne die interne Struktur redundant zu deklarieren.

Auch bei Code-Reviews lohnt sich ein Blick auf bestehende as Assertions: Viele davon lassen sich risikofrei durch satisfies ersetzen und gewinnen dadurch sofort an Sicherheit, ohne dass sich das Laufzeitverhalten der Anwendung in irgendeiner Weise ändert.

9. Fallstricke im Alltag

Ein häufiges Missverständnis ist, dass satisfies den deklarierten Typ der Variable verändert. Das ist nicht der Fall: Der resultierende Typ ist weiterhin der abgeleitete Typ des Ausdrucks, nicht der geprüfte Typ. Wer explizit den geprüften Typ als Variablentyp haben möchte, braucht weiterhin eine zusätzliche Annotation.

Ein zweiter Punkt betrifft die Mindestversion: satisfies erfordert TypeScript 4.9 oder neuer. In älteren Projekten, die noch auf einer früheren Version laufen, führt die Syntax zu einem Parserfehler. Auch die IDE-Autovervollständigung profitiert vom Feature: Beim Tippen innerhalb des Objektliterals schlägt der Editor bereits die Felder des Zieltyps vor, obwohl der resultierende Typ enger bleibt.

Ein dritter Fallstrick betrifft Build-Pipelines mit älteren Transpilern, die zwar den restlichen TypeScript-Code verstehen, aber noch nicht auf dem aktuellen Sprachstand basieren. Ein Upgrade der Toolchain sollte deshalb vor der Einführung von satisfies geprüft werden.

Merkmal Typannotation as Assertion satisfies
Strukturelle Prüfung Ja Nein Ja
Literal-Typen erhalten Nein Ja Ja
Fehlt eine Pflichteigenschaft Fehler Kein Fehler Fehler
Resultierender Typ der Variable Deklarierter Typ Assertierter Typ Abgeleiteter Typ des Ausdrucks
Mindestversion Alle Versionen Alle Versionen TypeScript 4.9+

Mironsoft

TypeScript-Migration, Typsicherheit und Team-Onboarding

JavaScript-Codebasis ohne Typsicherheit, aber keine Zeit für eine Rundum-Migration?

Wir migrieren bestehende JavaScript-Projekte schrittweise zu TypeScript, richten strikte Compiler-Einstellungen sauber ein und bringen Teams mit Code-Reviews und Style-Guides auf denselben Typsicherheits-Stand.

Migrations-Fahrplan

Schrittweise JS-zu-TS-Migration ohne Big-Bang-Risiko planen und umsetzen.

Strict-Mode-Einführung

tsconfig.json, ESLint-Regeln und CI-Checks für dauerhafte Typsicherheit aufsetzen.

Team-Onboarding

Entwickler mit Workshops und Code-Reviews in TypeScript-Best-Practices einarbeiten.

10. Zusammenfassung

Satisfies-Operator

Seit Version

TypeScript 4.9

Laufzeit-Overhead

Keiner, reines Compiler-Feature

Kombinierbar mit

as const, Record, Arrays

Typischer Einsatz

Konfigurationsobjekte, Lookup-Tabellen

11. FAQ: Satisfies-Operator

1Was macht der satisfies Operator in TypeScript genau?
Er prüft, ob ein Ausdruck strukturell zu einem angegebenen Typ passt, behält dabei aber den engeren, vom Ausdruck selbst abgeleiteten Typ bei, statt ihn auf den geprüften Typ zu weiten. So bekommt man Validierung und Präzision gleichzeitig, ohne einen der beiden Vorteile aufzugeben.
2Ab welcher TypeScript Version steht satisfies zur Verfügung?
satisfies wurde mit TypeScript 4.9 im November 2022 eingeführt und steht seitdem in allen neueren Versionen zur Verfügung. Projekte mit älteren Compiler-Versionen müssen zunächst ein Upgrade durchführen, um die Syntax nutzen zu können.
3Worin unterscheidet sich satisfies von einer normalen Typannotation?
Eine Typannotation weitet die Eigenschaften des Objekts auf die im Typ deklarierten Typen. satisfies prüft nur die Kompatibilität, der resultierende Typ bleibt der ursprüngliche, engere Typ des Ausdrucks, was besonders bei Literal-Werten einen spürbaren Unterschied macht.
4Worin unterscheidet sich satisfies von einer as Assertion?
Eine as Assertion führt keine echte strukturelle Prüfung durch und kann fehlende oder falsche Eigenschaften unbemerkt lassen. satisfies meldet solche Fehler bereits zur Kompilierzeit und ist damit die sicherere Wahl für neue Objektliterale.
5Kann satisfies mit as const kombiniert werden?
Ja, die Kombination ist ein gängiges Muster. as const fixiert alle Werte auf ihre engsten Literal-Typen, satisfies prüft zusätzlich die Struktur gegen ein Interface, sodass keine Pflichteigenschaft vergessen werden kann.
6Verändert satisfies den deklarierten Typ einer Variable?
Nein. Der Typ der Variable bleibt der vom Ausdruck abgeleitete Typ. satisfies dient ausschließlich der Validierung, nicht der Typdeklaration, weshalb eine zusätzliche Annotation nötig ist, falls der geprüfte Typ selbst gewünscht wird.
7Funktioniert satisfies auch mit Arrays und verschachtelten Objekten?
Ja, der Compiler prüft rekursiv jede Ebene der Struktur gegen den angegebenen Typ und erhält dabei auf jeder Ebene die konkreten Literal-Typen, auch bei tief verschachtelten Konfigurationsobjekten.
8Wann sollte man satisfies statt einer normalen Annotation verwenden?
Immer dann, wenn später mit den exakten Literal-Werten weitergearbeitet wird, etwa in switch-Anweisungen oder bei Funktionsparametern, die konkrete Literale erwarten. Für einfache, einmalig genutzte Variablen reicht dagegen oft eine normale Annotation.
9Gibt es einen Laufzeit-Unterschied durch satisfies?
Nein, satisfies ist ein reines Compiler-Feature ohne jede Auswirkung auf den erzeugten JavaScript-Code oder das Laufzeitverhalten. Der erzeugte Code ist identisch zu einer Version ohne satisfies.
10Verbessert satisfies die Autovervollständigung im Editor?
Ja, da der Ausdruck weiterhin gegen den Zieltyp geprüft wird, schlägt der Editor beim Tippen des Objektliterals bereits die erwarteten Felder des Zieltyps vor, was die Entwicklungsgeschwindigkeit spürbar erhöht.