Was verbirgt sich hinter der Prop children in React und TypeScript?
\n\nWenn Sie jemals eine React-Komponente mit TypeScript geschrieben haben, sind Sie sicherlich auf die Frage gestoßen: "Welchen Datentyp hat die Prop children?". Diese Frage ist eine der beliebtesten auf Stack Overflow, und das aus gutem Grund. Auf den ersten Blick scheint die Antwort einfach: ReactNode. Aber der Teufel steckt, wie man so schön sagt, im Detail.
In diesem Artikel geben wir nicht nur eine trockene Antwort. Wir analysieren alle möglichen Typen für children, ihre Unterschiede, Best Practices und Fallstricke. Sie erfahren, wann Sie ReactNode, wann ReactElement und wann spezifischere Typen verwenden sollten. Los geht's!
Warum ist diese Frage so beliebt?
\n\nDas Problem ist, dass children eine besondere Prop in React ist. Sie kann alles Mögliche sein:
- \n
- Ein String:
"Hallo, Welt!"\n - Eine Zahl:
{42}\n - Ein JSX-Element:
<div>...</div>\n - Ein Array von Elementen:
[<span/>, <span/>]\n - Eine Funktion (Render Prop):
{() => <div/>}\n - Sogar
null,undefinedoderboolean\n
Aufgrund dieser Flexibilität schreiben Anfänger oft children: any, was den gesamten Nutzen von TypeScript zunichte macht. Lassen Sie uns die richtigen Ansätze klären.
Die wichtigsten Typen für children
\n\n1. ReactNode – der Allrounder
\n\nDies ist der häufigste und in 90% der Fälle richtige Typ für children. Er umfasst alles, was React rendern kann.
import { ReactNode } from 'react';\n\ninterface CardProps {\n title: string;\n children: ReactNode;\n}\n\nfunction Card({ title, children }: CardProps) {\n return (\n <div className="card">\n <h2>{title}</h2>\n <div className="card-content">\n {children}\n </div>\n </div>\n );\n}\n\n// Verwendung:\n<Card title="Meine Karte">\n <p>Dieser Text wird gerendert</p>\n {123} {/* Zahlen funktionieren auch */}\n {null} {/* Und null */}\n</Card>\n\nWas gehört zu ReactNode? Tatsächlich ist es eine Vereinigung von:
\n- \n
ReactElement– JSX-Elemente \n stringundnumber– primitive Typen \n boolean,null,undefined– werden beim Rendern ignoriert \n ReactNode[]– ein Array der oben genannten \n ReactPortal– Portale \n
2. ReactElement – der strenge Modus
\n\nWenn Sie benötigen, dass children nur ein JSX-Element (kein String und keine Zahl) ist, verwenden Sie ReactElement.
import { ReactElement } from 'react';\n\ninterface StrictCardProps {\n children: ReactElement; // Nur ein JSX-Element\n}\n\nfunction StrictCard({ children }: StrictCardProps) {\n return <div className="strict-card">{children}</div>;\n}\n\n// Funktioniert:\n<StrictCard><span>Nur ein Element</span></StrictCard>\n\n// TypeScript-Fehler:\n<StrictCard>Text</StrictCard> // ❌ String ist nicht erlaubt\n\nWichtig: ReactElement erfordert genau ein untergeordnetes Element. Wenn Sie zwei Elemente ohne Klammer übergeben, gibt TypeScript ebenfalls einen Fehler aus.
3. JSX.Element – ein Alias für ReactElement
\n\nDer Typ JSX.Element ist einfach ReactElement<any, any>. Er ist weniger flexibel als ReactNode und wird normalerweise nicht für children empfohlen, es sei denn, Sie schreiben eine Bibliothek.
// Im Grunde ist es dasselbe:\ntype A = JSX.Element; // ReactElement<any, any>\ntype B = ReactElement; // Re