JSX.Element vs ReactNode vs ReactElement: Der Typenkampf, den Sie gewinnen müssen
Hallo, Kollege! Wenn du mit React und TypeScript arbeitest, bist du bestimmt schon in die Situation gekommen, dass der Compiler sich über die Typen der Rückgabewerte beschwert. "Expected JSX.Element, got ReactNode" – ein bekannter Fehler? Oder hast du ReactElement in Generics gesehen und dich gefragt: "Was ist überhaupt der Unterschied?"
Spoiler: Das sind nicht nur akademische Begriffe. Die richtige Typwahl kann deinen Code beschleunigen, Bugs verhindern und Komponenten vorhersagbarer machen. Heute analysieren wir dieses Thema anhand realer Beispiele, damit du diese drei Typen nie wieder verwechselst. Los geht's!
Kurze Einführung: Was ist was
Fangen wir mit den Grundlagen an. Alle drei Typen sind Teile eines Ökosystems, aber mit unterschiedlichem Abstraktionsgrad.
ReactElement
Dies ist der grundlegende Baustein. ReactElement ist ein Objekt mit Typ, Props und Key. Es stellt einen "Bauplan" eines Elements dar, den React später in einen echten DOM-Knoten verwandelt. Wenn du React.createElement('div', null, 'Hallo') schreibst, erhältst du genau ein ReactElement.
import React from 'react';
const element: React.ReactElement = React.createElement('div', { className: 'box' }, 'Hallo!');// Typ: ReactElement<{ className: string }, 'div'>Wichtig: ReactElement ist ein Generic. Du kannst den Typ der Props und den Elementtyp angeben:
type MyElement = React.ReactElement<{ name: string }, 'button'>;JSX.Element
Dies ist eine Erweiterung von ReactElement, die die JSX-Spezifikation hinzufügt. Im Grunde ist JSX.Element ein ReactElement<any, any>. Wenn du in JSX <div /> schreibst, sieht TypeScript genau JSX.Element.
const jsxElement: JSX.Element = <div>JSX.Element</div>;Der Hauptunterschied zu ReactElement ist, dass JSX.Element nicht parametrisiert wird. Es ist einfach ein "beliebiges JSX-Element".
ReactNode
Und das ist der breiteste Typ. ReactNode umfasst:
- ReactElement
- Strings
- Zahlen
- Booleans (true/false)
- null und undefined
- Arrays aus den oben genannten
- React Portal
Einfach ausgedrückt: ReactNode ist alles, was React rendern kann. Genau dieser Typ wird für children in Komponenten verwendet.
type ReactNode = | React.ReactElement | string | number | boolean | null | undefined | React.ReactNode[];Wann verwendet man was? Praktische Szenarien
Jetzt kommt der spannende Teil – lass uns analysieren, welchen Typ man in realen Situationen wählt.
Szenario 1: Rückgabewert einer Komponente
Deine Komponente gibt JSX zurück. Welchen Typ solltest du angeben?
// ❌ Schlecht: zu allgemeiner Typfunction MyComponent(): ReactNode { return <div>Hallo</div>;}
// ✅ Gut: JSX.Element verwendenfunction MyComponent(): JSX.Element { return <div>Hallo</div>;}
// ✅ Optimal: wenn eine strenge Typisierung der Props benötigt wirdfunction MyComponent(): React.ReactElement<{ title: string }> { return <div>Hallo</div>;}Warum? Eine Komponente gibt immer JSX (oder null, wenn sie nichts rendert) zurück. ReactNode ist zu breit – es erlaubt die Rückgabe eines Strings, einer Zahl oder eines Arrays, was zu unerwarteten Fehlern führen kann.
Szenario 2: children in einer Komponente
Hier ist ReactNode dein bester Freund. Kind-Elemente können alles sein: ein String, eine andere Komponente, null (bedingtes Rendern) oder ein Array.
interface CardProps { title: string; children: React.ReactNode; // ✅ Richtig}
function Card({ title, children }: CardProps): J