🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

TypeScript-Reaktionsmuster 2026: Generische Komponenten, Verbindungen und Hooks

⏱️5 min read  ·  1,079 words

Die TypeScript-React-Muster im Jahr 2026 gehen über die grundlegende Komponententypisierung hinaus. Zusammengesetzte Komponenten, Render-Requisiten, benutzerdefinierte Hooks mit komplexen Rückgabetypen und die neuen Serverkomponentenmuster von React 19 profitieren alle vom Typsystem von TypeScript. Dieser Leitfaden behandelt die Muster, die erfahrene React-Entwickler täglich verwenden.

Generische Komponenten

// Generic list component — renders any data type
interface ListProps<T> {
  items: T[];
  renderItem: (item: T, index: number) => React.ReactNode;
  keyExtractor: (item: T) => string | number;
  emptyComponent?: React.ReactNode;
  className?: string;
}

function List<T>({
  items,
  renderItem,
  keyExtractor,
  emptyComponent = <p>No items</p>,
  className,
}: ListProps<T>) {
  if (items.length === 0) return <>{emptyComponent}</>;

  return (
    <ul className={className}>
      {items.map((item, index) => (
        <li key={keyExtractor(item)}>
          {renderItem(item, index)}
        </li>
      ))}
    </ul>
  );
}

// Usage — fully type-safe
interface User { id: number; name: string; email: string; }

<List<User>
  items={users}
  keyExtractor={u => u.id}
  renderItem={user => (
    <UserCard user={user} />
  )}
/>

Polymorphe Komponenten

// A component that can render as any HTML element or component
type AsProp<T extends React.ElementType> = { as?: T };
type PropsToOmit<T extends React.ElementType, P> = keyof (AsProp<T> & P);

type PolymorphicComponentProp<T extends React.ElementType, Props = {}> = React.PropsWithChildren<
  Props & AsProp<T>
> &
  Omit<React.ComponentPropsWithoutRef<T>, PropsToOmit<T, Props>>;

type PolymorphicRef<T extends React.ElementType> = React.ComponentPropsWithRef<T>["ref"];

type PolymorphicComponentPropWithRef<T extends React.ElementType, Props = {}> =
  PolymorphicComponentProp<T, Props> & { ref?: PolymorphicRef<T> };

// Text component that renders as any element
interface TextProps {
  variant?: "h1" | "h2" | "h3" | "body" | "caption";
  color?: "primary" | "secondary" | "muted";
}

const variantMap = { h1: "h1", h2: "h2", h3: "h3", body: "p", caption: "span" } as const;

function Text<T extends React.ElementType = "span">({
  as,
  variant = "body",
  color = "primary",
  children,
  className,
  ...props
}: PolymorphicComponentProp<T, TextProps>) {
  const Component = as ?? variantMap[variant];
  return (
    <Component
      className={`text-${variant} text-${color} ${className ?? ""}`}
      {...props}
    >
      {children}
    </Component>
  );
}

// Usage
<Text variant="h1">Heading 1</Text>                 // renders <h1>
<Text as="label" htmlFor="email">Email</Text>        // renders <label>
<Text as={Link} to="/about" variant="body">About</Text>  // renders <Link>

Muster zusammengesetzter Komponenten

import { createContext, useContext, useState } from 'react';

// Accordion compound component
interface AccordionContextValue {
  openItem: string | null;
  setOpenItem: (id: string | null) => void;
}

const AccordionContext = createContext<AccordionContextValue | null>(null);

function useAccordion() {
  const ctx = useContext(AccordionContext);
  if (!ctx) throw new Error('Must be used within <Accordion>');
  return ctx;
}

function Accordion({ children, defaultOpen = null }: {
  children: React.ReactNode;
  defaultOpen?: string | null;
}) {
  const [openItem, setOpenItem] = useState<string | null>(defaultOpen);
  return (
    <AccordionContext.Provider value={{ openItem, setOpenItem }}>
      <div className="accordion">{children}</div>
    </AccordionContext.Provider>
  );
}

function AccordionItem({ id, title, children }: {
  id: string;
  title: string;
  children: React.ReactNode;
}) {
  const { openItem, setOpenItem } = useAccordion();
  const isOpen = openItem === id;

  return (
    <div className={`accordion-item ${isOpen ? 'open' : ''}`}>
      <button onClick={() => setOpenItem(isOpen ? null : id)}>
        {title}
        <span>{isOpen ? '▲' : '▼'}</span>
      </button>
      {isOpen && <div className="accordion-content">{children}</div>}
    </div>
  );
}

// Attach as namespaced components
Accordion.Item = AccordionItem;

// Usage
<Accordion defaultOpen="faq-1">
  <Accordion.Item id="faq-1" title="What is TypeScript?">
    TypeScript is a typed superset of JavaScript...
  </Accordion.Item>
  <Accordion.Item id="faq-2" title="Why use React?">
    React provides a declarative way to build UIs...
  </Accordion.Item>
</Accordion>

Typisierte benutzerdefinierte Haken

import { useCallback, useReducer } from 'react';

// Async state management hook
type AsyncState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; error: Error };

type AsyncAction<T> =
  | { type: 'start' }
  | { type: 'success'; data: T }
  | { type: 'error'; error: Error }
  | { type: 'reset' };

function asyncReducer<T>(state: AsyncState<T>, action: AsyncAction<T>): AsyncState<T> {
  switch (action.type) {
    case 'start': return { status: 'loading' };
    case 'success': return { status: 'success', data: action.data };
    case 'error': return { status: 'error', error: action.error };
    case 'reset': return { status: 'idle' };
  }
}

function useAsync<T, Args extends unknown[]>(
  fn: (...args: Args) => Promise<T>
) {
  const [state, dispatch] = useReducer(
    asyncReducer as React.Reducer<AsyncState<T>, AsyncAction<T>>,
    { status: 'idle' } as AsyncState<T>
  );

  const execute = useCallback(
    async (...args: Args) => {
      dispatch({ type: 'start' });
      try {
        const data = await fn(...args);
        dispatch({ type: 'success', data });
        return data;
      } catch (err) {
        const error = err instanceof Error ? err : new Error(String(err));
        dispatch({ type: 'error', error });
        throw error;
      }
    },
    [fn]
  );

  const reset = useCallback(() => dispatch({ type: 'reset' }), []);

  return { ...state, execute, reset };
}

// Usage with full type inference
function UserProfile({ userId }: { userId: number }) {
  const { status, data, error, execute } = useAsync(fetchUser);

  useEffect(() => { execute(userId); }, [userId]);

  if (status === 'loading') return <Spinner />;
  if (status === 'error') return <Error message={error.message} />;
  if (status === 'success') return <Profile user={data} />;  // data is User
  return null;
}

Reagieren Sie auf 19 Serverkomponenten mit TypeScript

// Server Component — no 'use client', runs on server
// app/blog/[slug]/page.tsx
import type { Metadata } from 'next';

interface Props {
  params: Promise<{ slug: string }>;
  searchParams: Promise<{ view?: string }>;
}

// Type-safe metadata generation
export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params;
  const post = await fetchPost(slug);

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [{ url: post.coverImage }],
    },
  };
}

export default async function PostPage({ params, searchParams }: Props) {
  const { slug } = await params;
  const { view = 'full' } = await searchParams;

  const post = await fetchPost(slug);
  if (!post) notFound();

  return (
    <article>
      <h1>{post.title}</h1>
      {view === 'full' ? (
        <div dangerouslySetInnerHTML={{ __html: post.contentHtml }} />
      ) : (
        <p>{post.excerpt}</p>
      )}
      <Suspense fallback={<CommentSkeleton />}>
        <Comments postId={post.id} />
      </Suspense>
    </article>
  );
}

// Client component with typed props
'use client';

interface CommentFormProps {
  postId: number;
  onSubmit: (comment: { text: string; author: string }) => Promise<void>;
}

function CommentForm({ postId, onSubmit }: CommentFormProps) {
  // ...client-side interactivity
}

Die TypeScript-React-Muster im Jahr 2026 sind ausgereift – generische Komponenten eliminieren doppelten Code, polymorphe Komponenten erstellen flexible APIs, zusammengesetzte Komponenten ersetzen komplexes Prop-Drilling und typisierte benutzerdefinierte Hooks machen asynchrone Muster sicher. Durch die Kombination der Serverkomponenten von React 19 mit TypeScript entstehen vollständig typsichere Full-Stack-Anwendungen.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা