Flow gegen TypeScript im Jahr 2026: Syntaktische Überschneidungen und strengere Überprüfungen
Erfahren Sie, wie die Syntax von Flow nun der von TypeScript entspricht, sowie seine einzigartigen Match-Expressionen, typspezifischen Eigenschaften für React und Laufzeitfehler, die TypeScript übersehen, aber Flow erkennt.
Bis 2026 hat sich Flow entlang von drei bemerkenswerten Entwicklungsrichtungen weiterentwickelt:
- Ihre Syntax überschneidet sich nun größtenteils mit der von TypeScript: Entwickler, die bereits TypeScript kennen, erkennen den größten Teil dessen, was Flow leistet.
- Sie bietet bestimmte Funktionen, die TypeScript noch nicht besitzt: am auffälligsten sind
match-Ausdrücke sowie spezielle Konstrukte für React wiecomponent,hookundrenders. - Wenn sich die beiden Typsysteme nicht einigen, neigt Flow dazu, die strengere Option zu wählen: Es weist Muster aus, die von TypeScript erlaubt werden, aber zu Laufzeit Probleme verursachen können, Daten heimlich beschädigen oder subtile Logikfehler einbringen.
Die Syntax von Flow und TypeScript hat sich angenähert
Betrachten Sie den folgenden Auszug – können Sie erkennen, ob es sich um Flow oder TypeScript handelt? Wahrscheinlich nicht.
type User = {
readonly name: string,
readonly age: number,
readonly metadata: unknown,
};
function get<K extends keyof User>(user: User, key: K): User[K] {
return user[key];
}
declare const user: User;
const age: number = get(user, 'age');
Jeder, der mit TypeScript vertraut ist, wird hier nichts Überraschendes finden. Das Beispiel nutzt keyof, readonly-Felder, den Typ unknown, indizierten Zugriff über T[K] sowie gebundene Generics mit extends. Flow unterstützt außerdem bedingte Typen, mappierte Typen, Type Guards sowie as const und ahmt somit das Werkzeugset von TypeScript sehr genau nach.
Der Rest dieses Artikels konzentriert sich auf die Bereiche, in denen Flow weiter geht als TypeScript.
Nur in Flow verfügbare Funktionen
Hier sind Fähigkeiten aufgeführt, die in Flow vorhanden sind, aber in TypeScript keinen Entsprechung haben.
match-Ausdrücke und -Anweisungen
Flow bietet eine match-Konstruktion für Musterabgleich als Ausdruck. Der Compiler überprüft diesen ausführlich und ermöglicht es Ihnen, Werte direkt im Zuge des Abgleichs zu destrukturieren. Wenn Sie einen Fall außer Acht lassen – zum Beispiel type: 'remove' – weist match dies aus und teilt Ihnen genau mit, was fehlt.
type Action =
| {type: 'add', text: string}
| {type: 'toggle', id: string}
| {type: 'remove', id: string};
declare const action: Action;
const description = match (action) { // ERROR: 'remove' case missing
{type: 'add', const text} => `Add: ${text}`,
{type: 'toggle', const id} => `Toggle ${id}`,
};
Es gibt auch eine Satzform von match, die sich wie ein switch verhält, bei dem kein Durchfall möglich ist, und über alle gleichen Funktionen wie die Ausdrucksversion verfügt.
React: component, hook, renders
component-Syntax: behandelt React-Komponenten als ein eingebautes Konzept auf Sprachebene. Props werden direkt als benannte Parameter deklariert, und der Typprüfer kann React-spezifische Korrektheitsregeln durchsetzen.
renders-Typen: Es ermöglicht die Beschreibung, wie Komponenten miteinander kombiniert werden. Design-Systeme und Komponentenbibliotheken können genau festlegen, was in einen Slot eingefügt werden darf und was eine Komponente erzeugen darf, wobei der Prüfer diese Vereinbarungen auch bei Wrapper-Komponenten durchsetzt.hook-Syntax: Markiert Hooks als eine eigene, vom normalen Funktionskonzept getrennte Kategorie. Flow integriert die Regeln von React direkt in seinen Typprüfer und erkennt dabei bedingte Aufrufe von Hooks, die Verwechslung von Hooks mit regulären Funktionen sowie unsichere Änderungen am Rückgabewert eines Hooks während der Renderung – und das ohne den Einsatz eines separaten ESLint-Plugins.component Header(text: string, color: string) {
return <div style={{color}}>{text}</div>;
}
component MainHeader(text: string) renders Header {
return <Header text={text} color="red" />;
}
component Layout(header: renders Header) {
return <div>
{header}
<section>Content</section>
</div>;
}
const ok = <Layout header={<MainHeader text="Flow" />} />;
const bad = <Layout header={<footer />} />; // ERROR
Vier Laufzeitkrisen, die TypeScript nicht erkennt – aber Flow schon
Hier gehen die beiden Typsysteme wirklich auseinander. Jedes der untenstehenden Beispiele besteht bei TypeScript 6.0.3 im strict-Modus die Typüberprüfung, scheitert jedoch dennoch zur Laufzeit.
- Durch das Entnehmen einer Methode aus einer Instanz geht in TypeScript die Verknüpfung mit
thisverloren
class Counter {
count: number = 0;
increment(): number {
return ++this.count;
}
}
const counter = new Counter();
const tick = counter.increment; // TS accepts. Flow rejects.
tick(); // Runtime crash! `this` is undefined inside `increment`
Sobald man counter.increment vom counter-Objekt entnimmt, ist es nicht mehr damit verknüpft – daher führt ein späterer Aufruf als tick() mit this als undefined zum Fehler, und ++this.count wirft eine Ausnahme. TypeScript behandelt die entnommene Methode als gewöhnliche Funktion und lässt den Aufruf ohne Beanstandung zu. Flow hingegen lehnt die Entnahme genau dort ab, wo die Verknüpfung mit this verloren geht.
- TypeScript erlaubt es, zusätzliche Eigenschaften durch indirekte Zuweisung einzuschleusen
type Prices = {apple: number, banana: number};
const items = {apple: 1.5, banana: 0.5, sample: "free"};
const prices: Prices = items; // TS accepts. Flow rejects.
Object.values(prices).map(
price => price.toFixed(2), // Runtime crash! `sample` isn't a number
);
Die Objekttypen von TypeScript erlauben technisch gesehen zusätzliche Eigenschaften. Die „Überprüfung auf überflüssige Eigenschaften“, die normalerweise etwas wie {apple: 1.5, sample: "free"} als Problem markiert, tritt nur dann in Kraft, wenn man ein Objektliteral direkt zuweist. Wenn derselbe Wert über eine Zwischenvariable geleitet wird, gilt diese Überprüfung nicht mehr – sodass das fehlende sample-Feld unentdeckt durchkommt. Die Objekttypen von Flow sind standardmäßig exakt, was bedeutet, dass zusätzliche Eigenschaften unabhängig davon abgelehnt werden, wie der Wert sein Ziel erreicht.
- In TypeScript kann ein weiterer Typ in einen engeren, veränderbaren Array eingefügt werden
// TypeScript: accepted.
function appendError(errs: Array<string | Error>) {
errs.push(new Error("oops"));
}
const errors: Array<string> = [];
appendError(errors); // TS accepts. Flow rejects.
errors[0].toUpperCase(); // Runtime crash! `errors[0]` isn't a string
Weil TypeScript veränderliche Arrays als kovariant betrachtet, gilt Array<string> als Untertyp von Array<string | Error>. Das bedeutet, dass der Aufruf akzeptiert wird, und der push-Aufruf in appendError führt dazu, dass ein Error in einen Array eingefügt wird, von dem der Aufrufer annahm, er enthalte nur string-Werte. Flow vermeidet dies, indem es veränderliche Arrays als invariante betrachtet und die Erweiterung direkt am Aufrufsort blockiert. Wenn eine Funktion keinen wirklichen Bedarf hat, ihre Eingabe zu verändern, beseitigt das Umstellen des Parameters auf ReadonlyArray<string | Error> das Risiko vollständig, da Unveränderlichkeit die Erweiterung harmlos macht.
- TypeScript überprüft nicht, was der Körper eines Type Guards tatsächlich tut
// TypeScript: accepted, but this body is true for numbers, not strings.
function isString(x: unknown): x is string {
return typeof x === "number"; // TS accepts. Flow rejects.
}
const data: unknown = 1;
if (isString(data)) {
data.toUpperCase(); // Runtime crash! `data` isn't a string
}
TypeScript überprüft nur die deklarierte Signatur eines Typprädikats – es prüft niemals, was der Funktionskörper tatsächlich zurückgibt. Flow prüft beide Richtungen: Jede return-Anweisung muss tatsächlich auf den Zieltyp der Bedingung eingegrenzt werden, und der else-Ast muss diesen Typ korrekt ausschließen. Infolgedessen lehnt Flow Prädikate ab, deren Logik nicht mit dem übereinstimmt, was sie angeblich überprüfen sollen.
Vollständige Vergleichsanalyse lesen
Für eine umfangreichere Sammlung an Beispielen bietet die eigene Dokumentationsseite von Flow eine ausführliche Darstellung, die die beiden Sprachen Punkt für Punkt vergleicht und mehr als zwanzig weitere Fälle behandelt, die hier nicht gezeigt werden: Vergleichsleitfaden ansehen.
Zusätzliche Literatur
- Die Standarde für Full-Stack JavaScript im Jahr 2026: TypeScript, RSC und mehr — Erklärt, warum TypeScript, React Server Components sowie ein effizienterer Ansatz zur Zustandsverwaltung 2026 zum Standard für JavaScript-Entwicklerteams geworden sind.
- TC39-Vorschläge im Jahr 2026: Erklärung zu Decorators, Temporal und Signals — Eine praktische Übersicht über drei TC39-Vorschläge – native Decorators, die Temporal-API sowie Signals – und ihre Bedeutung für Full-Stack-JavaScript- und TypeScript-Entwickler.