Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

TypeScript zum React-Projekt hinzufügen

TypeScript zum Projekt hinzufügen

~14 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026

Ab hier migrieren wir produktkatalog-web schrittweise zu TypeScript. WICHTIG: Dieses und die nächsten drei Kapitel zeigen, WIE man TypeScript MIT React kombiniert – Props typisieren, Hooks typisieren, Events typisieren. Die TypeScript-SPRACHE selbst (jedes Feature von Grund auf, interface vs. type, Generics, Utility-Types, ...) wird sehr ausführlich in einem eigenen, separaten TypeScript-Tutorial behandelt – hier setzen wir grundlegende TypeScript-Kenntnisse voraus und konzentrieren uns auf die React-INTEGRATION.

Warum TypeScript für ein React-Projekt lohnt

Erinnern Sie sich an Bugs wie "product.price.toFixed ist keine Funktion", weil price unerwartet ein String statt einer Zahl war? Oder an einen Tippfehler in einem Prop-Namen (onAddToCard statt onAddToCart), der erst beim Testen im Browser auffiel? TypeScript fängt beide Fehlerklassen bereits WÄHREND des Tippens im Editor ab, VOR dem ersten Ausführen.

Vite-Projekt auf TypeScript umstellen

Vite unterstützt TypeScript nativ – keine separate Build-Pipeline nötig, nur die richtigen Pakete und Dateiendungen. Installieren Sie die TypeScript-Typdefinitionen für React:

npm install --save-dev typescript @types/react @types/react-dom

tsconfig.json anlegen

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"]
}
  • "noEmit": true – TypeScript wird hier NUR zur Typprüfung genutzt, nicht zum Kompilieren; Vite/esbuild übernehmen das eigentliche Kompilieren (und entfernen die Typen dabei einfach).
  • "jsx": "react-jsx" – aktiviert die moderne JSX-Transformation, die kein import React from 'react' mehr in jeder Datei benötigt (identisch zu Vites JavaScript-Voreinstellung).
  • "strict": true – aktiviert ALLE strengen Typprüfungen auf einmal (u. a. strictNullChecks, ohne das null/undefined praktisch überall erlaubt wären) – für ein neues Projekt IMMER empfohlen, nachträgliches Aktivieren in einer großen bestehenden Codebase ist deutlich schmerzhafter.

Die erste Datei umstellen: utils/bmi.js-Äquivalent hier cartSlice.js

TypeScript-Dateien mit JSX-Syntax bekommen die Endung .tsx, reine Logikdateien ohne JSX .ts. Beginnen wir mit einer Datei OHNE JSX – src/store/cartSlice.js wird zu cartSlice.ts:

src/store/cartSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

export interface CartItem {
  sku: string;
  name: string;
  price: number;
  quantity: number;
}

interface CartState {
  items: CartItem[];
}

const initialState: CartState = { items: [] };

const cartSlice = createSlice({
  name: 'cart',
  initialState,
  reducers: {
    addItem(state, action: PayloadAction>) {
      const { sku, name, price } = action.payload;
      const existing = state.items.find((item) => item.sku === sku);
      if (existing) {
        existing.quantity += 1;
      } else {
        state.items.push({ sku, name, price, quantity: 1 });
      }
    },
    removeItem(state, action: PayloadAction<string>) {
      state.items = state.items.filter((item) => item.sku !== action.payload);
    },
    updateQuantity(state, action: PayloadAction<{ sku: string; quantity: number }>) {
      const { sku, quantity } = action.payload;
      const item = state.items.find((item) => item.sku === sku);
      if (item) {
        item.quantity = Math.max(1, quantity);
      }
    },
    clearCart(state) {
      state.items = [];
    },
  },
});

export const { addItem, removeItem, updateQuantity, clearCart } = cartSlice.actions;
export default cartSlice.reducer;

export interface CartItem ist der wichtigste neue Baustein: eine wiederverwendbare Typ-Definition, die wir in den nächsten Kapiteln in MEHREREN Dateien importieren werden (ProductCard, CartPage, ...) – EIN einziger Ort, der beschreibt, "was ein Warenkorb-Artikel ist". PayloadAction<T> ist Redux Toolkits eigener generischer Typ für Actions – T beschreibt die Form von action.payload. Omit<CartItem, 'quantity'> nimmt CartItem und ENTFERNT das quantity-Feld – exakt passend zu unserem addItem-Aufruf, der niemals eine Menge übergibt (die wird intern immer auf 1 gesetzt oder erhöht).

src/store/index.js zu index.ts

src/store/index.ts
import { configureStore } from '@reduxjs/toolkit';
import cartReducer from './cartSlice';

export const store = configureStore({
  reducer: {
    cart: cartReducer,
  },
});

// Aus dem Store SELBST abgeleitete Typen - müssen nie manuell synchron gehalten werden,
// da sie sich automatisch an Änderungen im Store anpassen:
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

ReturnType<typeof store.getState> ist ein klassisches TypeScript-Muster: statt RootState von Hand nachzupflegen (fehleranfällig, gerät leicht außer Synchronisation), wird der Typ AUTOMATISCH aus der tatsächlichen Store-Konfiguration ABGELEITET. RootState/AppDispatch werden im nächsten Kapitel für typsichere useSelector/useDispatch-Aufrufe gebraucht.

Achtung: Ab jetzt können .js/.jsx- und .ts/.tsx-Dateien im selben Projekt KOEXISTIEREN – die Migration muss nicht auf einmal passieren. Genau so gehen wir in den nächsten Kapiteln vor: Datei für Datei umstellen, nicht alles gleichzeitig.