Praxis
TypeScript mit React: Komponenten richtig typisieren
Props, State, Events und Refs in React-Komponenten mit TypeScript typisieren. Praxisbeispiele für funktionale Komponenten und Hooks.
Inhalt
TypeScript mit React: Komponenten richtig typisieren
React und TypeScript ergänzen sich hervorragend. TypeScript gibt dir Typsicherheit für Props, State, Event-Handler und Refs, und macht es deutlich einfacher, Fehler frühzeitig zu finden. Dieser Ratgeber zeigt die wichtigsten Muster für die tägliche Arbeit.
Props typisieren
Der häufigste Anwendungsfall ist das Definieren eines Interfaces für die Props einer Komponente.
interface KnopfProps {
beschriftung: string;
onClick: () => void;
deaktiviert?: boolean;
variante?: "primaer" | "sekundaer" | "gefahr";
}
function Knopf({ beschriftung, onClick, deaktiviert = false, variante = "primaer" }: KnopfProps) {
return (
<button
onClick={onClick}
disabled={deaktiviert}
className={`btn btn-${variante}`}
>
{beschriftung}
</button>
);
}
TypeScript prüft beim Aufruf, ob alle Pflicht-Props angegeben sind und ob die Typen stimmen.
Children typisieren
Wenn deine Komponente Kinder-Elemente akzeptiert, verwendest du React.ReactNode als Typ.
interface KarteProps {
titel: string;
children: React.ReactNode;
}
function Karte({ titel, children }: KarteProps) {
return (
<div className="karte">
<h2>{titel}</h2>
<div className="karte-inhalt">{children}</div>
</div>
);
}
useState mit Typen
React leitet den Typ von useState aus dem Initialwert ab. Bei komplexeren Strukturen oder wenn der Initialwert null ist, gibst du den Typen explizit an.
interface Formularwerte {
name: string;
email: string;
nachricht: string;
}
function KontaktFormular() {
const [werte, setWerte] = React.useState<Formularwerte>({
name: "",
email: "",
nachricht: "",
});
const [fehler, setFehler] = React.useState<string | null>(null);
const [gesendet, setGesendet] = React.useState(false);
// TypeScript weiß: werte ist Formularwerte, fehler ist string | null, gesendet ist boolean
return <div>{/* ... */}</div>;
}
Event-Handler typisieren
Event-Handler in React haben spezifische Typen, die vom Element und der Art des Events abhängen.
function Suche() {
const [suchbegriff, setSuchbegriff] = React.useState("");
const handleAenderung = (event: React.ChangeEvent<HTMLInputElement>) => {
setSuchbegriff(event.target.value);
};
const handleAbsenden = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log("Suche nach:", suchbegriff);
};
return (
<form onSubmit={handleAbsenden}>
<input
type="text"
value={suchbegriff}
onChange={handleAenderung}
placeholder="Suchbegriff eingeben"
/>
<button type="submit">Suchen</button>
</form>
);
}
useRef typisieren
useRef wird für DOM-Referenzen und für veränderbare Werte verwendet, die kein Re-Render auslösen sollen.
function FokusEingabe() {
// DOM-Referenz: Typ des Elements angeben, null als Initialwert
const eingabeRef = React.useRef<HTMLInputElement>(null);
const fokussieren = () => {
// Optional Chaining nötig, da ref.current null sein kann
eingabeRef.current?.focus();
};
return (
<div>
<input ref={eingabeRef} type="text" />
<button onClick={fokussieren}>Fokussieren</button>
</div>
);
}
useReducer mit Typen
Bei komplexem State ist useReducer oft sauberer als mehrere useState-Aufrufe. TypeScript hilft dabei, alle Action-Typen vollständig zu behandeln.
type AufgabeAktion =
| { type: "HINZUFUEGEN"; titel: string }
| { type: "ABSCHLIESSEN"; id: number }
| { type: "LOESCHEN"; id: number };
interface Aufgabe {
id: number;
titel: string;
erledigt: boolean;
}
interface AufgabenZustand {
aufgaben: Aufgabe[];
naechsteId: number;
}
function aufgabenReducer(zustand: AufgabenZustand, aktion: AufgabeAktion): AufgabenZustand {
switch (aktion.type) {
case "HINZUFUEGEN":
return {
aufgaben: [
...zustand.aufgaben,
{ id: zustand.naechsteId, titel: aktion.titel, erledigt: false },
],
naechsteId: zustand.naechsteId + 1,
};
case "ABSCHLIESSEN":
return {
...zustand,
aufgaben: zustand.aufgaben.map((a) =>
a.id === aktion.id ? { ...a, erledigt: true } : a
),
};
case "LOESCHEN":
return {
...zustand,
aufgaben: zustand.aufgaben.filter((a) => a.id !== aktion.id),
};
}
}
Der Compiler prüft, ob alle Fälle behandelt wurden. Vergisst du einen case, gibt es einen Fehler.
Generische Komponenten
Manchmal willst du eine Komponente, die mit verschiedenen Datentypen funktioniert. Dann verwendest du generische Komponenten.
interface ListenProps<T> {
elemente: T[];
renderElement: (element: T, index: number) => React.ReactNode;
leerText?: string;
}
function Liste<T>({ elemente, renderElement, leerText = "Keine Einträge" }: ListenProps<T>) {
if (elemente.length === 0) {
return <p>{leerText}</p>;
}
return (
<ul>
{elemente.map((element, index) => (
<li key={index}>{renderElement(element, index)}</li>
))}
</ul>
);
}
Im Playground ausprobieren
Das Playground unterstützt React und JSX direkt. Du kannst dort Komponenten typisieren und sofort sehen, welche Fehler TypeScript meldet, wenn Props fehlen oder Events falsch typisiert sind. Das ist ein effizienter Weg, neue Muster auszuprobieren, bevor du sie in ein echtes Projekt überträgst.
Fazit
TypeScript macht React-Code robuster und selbstdokumentierend. Props-Interfaces beschreiben den Vertrag einer Komponente. Korrekt typisierte Event-Handler verhindern Tippfehler bei Property-Zugriffen. Wer diese Grundmuster verinnerlicht, profitiert sofort von weniger Laufzeitfehlern und besserer IDE-Unterstützung.
Häufige Fragen
Soll ich React.FC oder direkt function für meine Komponenten verwenden?
Direkt function ist heute die bevorzugte Variante. React.FC fügt implizit children zu den Props hinzu und macht den Rückgabetyp weniger flexibel. Mit der direkten Funktionssyntax hast du mehr Kontrolle und der Code ist klarer.
Wie typisiere ich einen Event-Handler für ein input-Element?
Verwende React.ChangeEvent<HTMLInputElement> für den onChange-Handler. Für Submit-Events bei Formularen ist React.FormEvent<HTMLFormElement> der richtige Typ.
Quellen
- React TypeScript Cheatsheet (react-typescript-cheatsheet.netlify.app)
Über die Autorenschaft
Jan-Tristan Rudat
Redakteur typescript-playground.de
Themengebiet: Generationen, Kulturgeschichte, Sternzeichen, Pop-Phänomene rund ums Alter
Mehr über Jan-Tristan Rudat →Verwandte Artikel
Grundlagen
Was ist TypeScript? Eine Einführung in die typisierte JavaScript-Erweiterung
TypeScript erweitert JavaScript um statische Typen und macht große Codebases wartbarer. Lerne die Grundlagen, die Geschichte und die wichtigsten Vorteile von TypeScript.
Lesezeit 7 Min.
Grundlagen
TypeScript vs. JavaScript: Die wichtigsten Unterschiede im Überblick
TypeScript und JavaScript unterscheiden sich grundlegend in der Typprüfung, Werkzeugunterstützung und Wartbarkeit. Dieser Ratgeber erklärt die Unterschiede und hilft bei der Wahl der richtigen Sprache.
Lesezeit 8 Min.
Typen
TypeScript Typen Grundlagen: string, number, boolean und mehr
Die primitiven Typen string, number und boolean sind das Fundament von TypeScript. Dieser Ratgeber erklärt alle grundlegenden Typen mit praktischen Beispielen.
Lesezeit 9 Min.