NCA Social Media
Aktualisiert:
Autor:
Roland Golla
Grüner Browser mit Wortmarke TypeScript never, TS Kachel links und Rakete rechts

Was ist der never Type in TypeScript?

never ist der TypeScript Type für Werte, die niemals auftreten. Kein einziger Wert lässt sich einer Variable vom Typ never zuweisen. Umgekehrt ist never selbst jedem anderen Type zuweisbar. Der Compiler nutzt never überall dort, wo ein Codepfad rechnerisch unmöglich ist.

Eingeführt wurde never mit TypeScript 2.0. Es ist der sogenannte Bottom Type des Typsystems, das Gegenstück zum Top Type unknown. unknown sagt: Hier kann alles drin sein. never sagt: Hier kann gar nichts drin sein. Zwei Situationen erzeugen never automatisch: Funktionen, die nie normal zurückkehren (throw oder Endlosschleife), und Union Types, die durch Narrowing komplett leergelaufen sind.

Der praktische Wert steckt in der zweiten Situation. Wenn du einen Union Type in einem switch abarbeitest und alle Fälle behandelst, bleibt am Ende never übrig. Kommt später ein neuer Fall in die Union und du vergisst den switch, ist der Rest eben nicht mehr never, und der Compiler bricht ab. Genau das nennt man Exhaustive Check. Es ist die stärkste Waffe gegen vergessene Fälle, und sie kostet drei Zeilen Code.

Wer aus der PHP Welt kommt, kennt das Prinzip von PHPStan und Psalm: Der Analyzer meldet unerreichbaren Code und nicht abgedeckte Fälle. In TypeScript ist dieses Wissen direkt Teil der Sprache.

never mit NCA: Schnelle Hilfe vom Experten

Never Code Alone arbeitet seit über 20 Jahren an Softwarequalität. Unser Frontend Stack aus Astro, React und Vue läuft durchgehend typisiert in Production, Type Checking ist Pflichtschritt in jeder unserer Pipelines. Exhaustive Checks mit never sind bei uns kein Lehrbuchbeispiel, sondern Standard in jedem Union Type, der mehr als zwei Fälle hat. Das Denken kennen wir aus PHP: PHPStan auf Maximallevel und Type Coverage machen im Backend genau das, was never im Frontend macht.

Wir bringen dieses Wissen direkt in dein Projekt. Wir refactoren gewachsene TypeScript Codebasen, führen den strict Mode in bestehenden Projekten ein und räumen mit Knip ungenutzten Code weg. Im Vibe Coding Consulting zeigen wir Teams, wie sie KI generierten Code mit Typen absichern statt ihm zu vertrauen. Die Vibe Coding Best Practices von NCA behandeln genau diese Guardrails, und in der Symfony Welt setzen wir dieselbe Strenge mit Rector und Psalm um.

Lass uns sprechen

Finde das passende Angebot für dein Projekt

🤖

Hey! Ich bin CodeBot. Lass uns herausfinden, wie wir dein Projekt zum Fliegen bringen.

Was soll entstehen?

Beispiel 1: Funktionen, die niemals zurückkehren

Der einfachste Einstieg. Eine Funktion, die immer einen Fehler wirft, gibt nichts zurück. Aber sie gibt auch kein undefined zurück, wie es bei void der Fall wäre. Sie kehrt schlicht nie zurück. Genau das ist never.

Code:
          

function fail(message: string): never {
  throw new Error(message);
}

function endlessWorker(): never {
  while (true) {
    processQueue();
  }
}

Der Unterschied zu void wird an dieser Stelle zum ersten Mal greifbar. Eine void Funktion läuft durch und liefert undefined. Eine never Funktion erreicht ihr Ende nie.

Code:
          

function logIt(msg: string): void {
  console.log(msg);
  // kommt hier an, gibt undefined zurueck
}

function crash(msg: string): never {
  throw new Error(msg);
  // kommt hier nie an
}

Der praktische Nutzen: Der Compiler versteht Control Flow. Eine Funktion mit Rückgabetyp never beendet den Codepfad. Alles danach ist unerreichbar, und das Narrowing rechnet damit.

Code:
          

function getUser(id: string | null): string {
  if (id === null) {
    fail('ID fehlt');
  }

  // TypeScript weiss hier: id ist string, nicht null
  return id.toUpperCase();
}

Ohne den never Rückgabetyp bei fail würde TypeScript hier meckern, weil id theoretisch noch null sein könnte. Mit never ist der Fall erledigt. Ein kleiner Trick mit großer Wirkung in Guard Clauses.

Beispiel 2: Der Exhaustive Check mit assertNever

Das ist der Fall, für den sich der ganze Artikel lohnt. Du hast einen Union Type und arbeitest ihn in einem switch ab. Ohne Exhaustive Check passiert bei einer Erweiterung der Union genau nichts. Der Code kompiliert, und in Production kommt undefined raus.

Code:
          

type Status = 'draft' | 'review' | 'published';

function label(status: Status): string {
  switch (status) {
    case 'draft':
      return 'Entwurf';
    case 'review':
      return 'In Pruefung';
    case 'published':
      return 'Veroeffentlicht';
  }
}

Jetzt kommt der Status archived dazu. Die Union wächst, der switch bleibt wie er ist. Der Compiler warnt nur, wenn noImplicitReturns aktiv ist, und selbst dann ist die Fehlermeldung unscharf. Mit never wird der Fehler explizit und zeigt genau auf den vergessenen Fall.

Code:
          

function assertNever(value: never): never {
  throw new Error('Unbehandelter Fall: ' + JSON.stringify(value));
}

type Status = 'draft' | 'review' | 'published' | 'archived';

function label(status: Status): string {
  switch (status) {
    case 'draft':
      return 'Entwurf';
    case 'review':
      return 'In Pruefung';
    case 'published':
      return 'Veroeffentlicht';
    default:
      return assertNever(status);
      // Fehler: Argument of type 'archived'
      // is not assignable to parameter of type 'never'
  }
}

Der Compiler bricht ab, bevor irgendetwas deployed wird. Und die Fehlermeldung nennt den vergessenen Wert beim Namen. Genau so soll ein Fehler aussehen.

Das Muster funktioniert genauso mit Discriminated Unions, also Objekt Unions mit gemeinsamem Feld. Das ist der Alltag in jedem State Management und in jeder API Antwort.

Code:
          

type ApiResult =
  | { kind: 'success'; data: string[] }
  | { kind: 'error'; message: string }
  | { kind: 'loading' };

function render(result: ApiResult): string {
  switch (result.kind) {
    case 'success':
      return result.data.join(', ');
    case 'error':
      return 'Fehler: ' + result.message;
    case 'loading':
      return 'Laedt...';
    default:
      return assertNever(result);
  }
}

Der zweite Vorteil ist die Laufzeit. assertNever wirft einen echten Fehler, wenn zur Laufzeit doch ein unbekannter Wert ankommt, etwa aus einer API, die sich geändert hat. Compile Time Sicherheit und Runtime Sicherheit in einer Funktion. In Tests ist dieser Fehler dann sofort sichtbar statt still zu verschwinden.

Wer keine eigene Helper Funktion schreiben will, nutzt die Variante mit einer Variablen. Gleiches Ergebnis, weniger Code.

Code:
          

default: {
  const exhaustive: never = result;
  throw new Error('Unbehandelt: ' + exhaustive);
}

never, void, unknown und any im Vergleich

Type Bedeutung Typischer Einsatz
never Kein Wert ist zuweisbar, der Bottom Type Exhaustive Checks, Funktionen die immer werfen, Union Filter
void Rückgabewert wird ignoriert, faktisch undefined Funktionen ohne Rückgabewert, Event Handler
unknown Jeder Wert ist zuweisbar, der Top Type, aber nicht nutzbar ohne Prüfung API Antworten, JSON Parsing, fremde Daten
any Jeder Wert ist zuweisbar, alle Prüfungen abgeschaltet Notausgang, in sauberem Code vermeiden

Beispiel 3: never filtert Union Types in Conditional Types

Hier wird never zum Werkzeug statt zum Warnsignal. In einem Conditional Type verhält sich never wie die leere Menge: Was zu never wird, verschwindet aus der Union. Genau darauf bauen die eingebauten Utility Types auf.

Code:
          

// So ist Exclude in TypeScript definiert
type Exclude<T, U> = T extends U ? never : T;

type Rolle = 'admin' | 'editor' | 'guest';
type Intern = Exclude<Rolle, 'guest'>;
// Ergebnis: 'admin' | 'editor'

Jeder Zweig, der never liefert, fällt aus dem Ergebnis heraus. Dasselbe Prinzip steckt in NonNullable.

Code:
          

type NonNullable<T> = T extends null | undefined ? never : T;

type Eingabe = string | null | undefined;
type Sauber = NonNullable<Eingabe>;
// Ergebnis: string

Mit dem Muster baust du eigene Filter. Ein häufiger Fall im Alltag: alle Keys eines Objekts finden, die einen bestimmten Werttyp haben. Zum Beispiel alle Textfelder eines Formulars.

Code:
          

type KeysMitTyp<T, V> = {
  [K in keyof T]: T[K] extends V ? K : never;
}[keyof T];

interface Formular {
  name: string;
  email: string;
  alter: number;
  aktiv: boolean;
}

type Textfelder = KeysMitTyp<Formular, string>;
// Ergebnis: 'name' | 'email'

Der Trick: Jeder Key, der nicht passt, wird auf never gemappt. Beim Zugriff über keyof T verschwinden alle never Einträge automatisch. Übrig bleibt exakt die gewünschte Liste. Solche Typen sind Gold wert, wenn generische Formular Komponenten oder Tabellen typisiert werden sollen.

Ein zweites Muster verhindert falsche Aufrufe schon in der Signatur. Ein Parameter vom Typ never kann nie befüllt werden, also ist der Aufruf schlicht unmöglich.

Code:
          

type NurStrings<T> = T extends string ? T : never;

function ausgeben<T>(wert: NurStrings<T>): void {
  console.log(wert);
}

ausgeben<string>('ok');
ausgeben<number>(42);
// Fehler: Argument of type 'number'
// is not assignable to parameter of type 'never'

Beispiel 4: never als Fehlersignal, wenn die IDE plötzlich never anzeigt

Viele Entwickler begegnen never zum ersten Mal als Fehlermeldung. Der Compiler sagt sinngemäß: Dieser Wert kann nicht existieren. Meist steckt einer dieser drei Fälle dahinter.

Fall 1: Das leere Array ohne Typ. Ein Array ohne Angabe und ohne Inhalt hat den Typ never Array. Jeder push scheitert.

Code:
          

const eintraege = [];
// Typ: never[]

eintraege.push('Hallo');
// Fehler: Argument of type 'string'
// is not assignable to parameter of type 'never'

// Loesung:
const richtig: string[] = [];
richtig.push('Hallo');

Fall 2: Die unmögliche Intersection. Zwei Typen, die sich widersprechen, ergeben zusammen never. Das passiert schnell bei generischen Constraints oder bei zusammengeführten Konfigurationsobjekten.

Code:
          

type Unmoeglich = string & number;
// Typ: never

type Modus = 'hell' & 'dunkel';
// Typ: never

Fall 3: Narrowing bis zum Ende. Nach allen Prüfungen bleibt nichts übrig. Wenn die IDE hier never zeigt, ist das die gute Nachricht: Der Exhaustive Check greift.

Code:
          

function pruefen(wert: string | number): void {
  if (typeof wert === 'string') {
    return;
  }
  if (typeof wert === 'number') {
    return;
  }

  // wert hat hier den Typ never
  console.log(wert);
}

Faustregel für die Praxis: never an einer erwarteten Stelle ist ein Feature. never an einer unerwarteten Stelle ist ein Hinweis auf eine falsche Typdefinition. In beiden Fällen weiß der Compiler mehr über den Code als der Entwickler in dem Moment.

Warum never beim KI Coding zum Sicherheitsnetz wird

KI Agents schreiben Code schnell und meistens plausibel. Genau das ist das Problem. Ein Modell ergänzt eine Union um einen neuen Fall, weil die Anforderung es verlangt, und rührt den switch drei Dateien weiter nicht an. Der Code sieht korrekt aus, kompiliert und liefert in einem Fall undefined. Kein Test schlägt an, wenn dieser Fall nicht getestet wird.

Der Exhaustive Check dreht das um. Er macht aus einer stillen Lücke einen harten Compilerfehler. Und ein Compilerfehler ist Feedback, das der KI Agent selbst lesen kann. Er fixt den Fall in derselben Session, ohne dass ein Mensch eingreifen muss.

Drei typische KI Fehlerklassen, die never abfängt:

  • Vergessene Cases: Die Union wächst, die Behandlung nicht. Der Klassiker bei Feature Erweiterungen durch Agents.
  • Halluzinierte Werte: Das Modell erfindet einen Status, den es im Type nicht gibt. Der switch akzeptiert ihn nicht.
  • Toter Code: Ein Zweig, den das Modell defensiv ergänzt hat, ist rechnerisch unerreichbar. never zeigt es sofort.

Damit das greift, muss der Agent die Regel kennen. In der CLAUDE.md oder der jeweiligen Regeldatei gehört sie explizit hinterlegt.

Code:
          

## Type Regeln
- Jeder switch ueber einen Union Type endet mit assertNever im default
- Kein any, im Zweifel unknown mit anschliessender Pruefung
- Neue Union Faelle immer zusammen mit allen switch Stellen erweitern

## Vor jedem Commit
- npx tsc --noEmit muss gruen sein

Der zweite Baustein ist die Pipeline. tsc --noEmit läuft als eigener Schritt, getrennt vom Build. Der Typecheck ist die Instanz, die KI Code abnimmt, bevor ein Mensch ihn reviewt.

Code:
          

# Lokal vor dem Commit
npx tsc --noEmit

# Dauerhaft im Watch Mode waehrend der Agent arbeitet
npx tsc --noEmit --watch

Das ist der Kern von Vibe Coding Consulting bei NCA: Nicht die KI bremsen, sondern Guardrails bauen, die schneller sind als der Mensch. Die Typen sind dabei die günstigste Absicherung, die es gibt. Sie kosten keine Laufzeit, keine Testinfrastruktur und keinen Reviewtermin. Welche Modelle wir dafür einsetzen, steht in unserem Überblick zu KI Modellen für Entwickler und in der Einordnung, welches KI Modell ohne US Anbieter passt.

Im PHP Backend ist die Logik dieselbe. Ein match Ausdruck ohne default wirft bei unbehandelten Fällen einen Fehler, und PHPStan meldet nicht abgedeckte Zweige. Wer beide Seiten so absichert, bekommt KI Code, der sich selbst korrigiert. Type Perfect zieht die Schrauben dort noch fester an.

never in React, Astro und in der CI Pipeline

Im Frontend zahlt sich never überall dort aus, wo aus Daten UI wird. Eine Komponente rendert je nach Variante etwas anderes. Kommt eine Variante dazu, muss jede Stelle nachziehen.

Code:
          

type ButtonVariante = 'primary' | 'secondary' | 'danger';

function klassen(variante: ButtonVariante): string {
  switch (variante) {
    case 'primary':
      return 'btn btn-primary';
    case 'secondary':
      return 'btn btn-secondary';
    case 'danger':
      return 'btn btn-danger';
    default:
      return assertNever(variante);
  }
}

Dasselbe Muster in einer React Komponente mit Ladezustand. Jeder Zustand bekommt sein Markup, kein Zustand fällt hinten runter.

Code:
          

type Zustand =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'error'; fehler: string }
  | { status: 'done'; items: string[] };

function Liste({ zustand }: { zustand: Zustand }) {
  switch (zustand.status) {
    case 'idle':
      return null;
    case 'loading':
      return <Spinner />;
    case 'error':
      return <Fehler text={zustand.fehler} />;
    case 'done':
      return <Items items={zustand.items} />;
    default:
      return assertNever(zustand);
  }
}

In Astro Projekten gilt dasselbe für Props von Islands und für Content Collections mit unterschiedlichen Eintragstypen. Der Typecheck läuft dabei nicht im Browser, sondern in der Pipeline.

Code:
          

# GitHub Actions Schritt
- name: Type Check
  run: npx tsc --noEmit

# Astro Projekte
- name: Astro Check
  run: npx astro check

Wichtig ist die Trennung: Der Typecheck ist ein eigener Schritt, kein Nebeneffekt des Builds. Bundler wie Vite bauen weiter, egal wie kaputt die Typen sind. Erst ein eigener Schritt macht den Fehler sichtbar und die Pipeline rot. Wie wir Pipelines aufsetzen, zeigen unsere Best Practices für KI gestützte Entwicklung.

The never type is assignable to every type; however, no type is assignable to never.

TypeScript Handbook, Offizielle TypeScript Dokumentation von Microsoft – typescriptlang.org, Kapitel Narrowing

Aus der NCA Praxis: never ist die billigste Versicherung im Projekt

In Beratungsprojekten sehen wir regelmäßig dasselbe Muster. Ein Union Type wächst über Monate, die switch Stellen verteilen sich über die Codebasis, und irgendwann rendert die UI einen leeren Zustand, den niemand erklären kann. Der Fix ist eine Funktion mit vier Zeilen. Der Schaden vorher waren Tage im Debugging.

Wir bauen diese Guardrails bei Vibe Coding Consulting und in klassischen Refactoring Projekten ein: strict Mode aktivieren, Exhaustive Checks setzen, Knip gegen toten Code laufen lassen und den Typecheck als eigenen Schritt in die Pipeline hängen. Im Backend gilt dieselbe Strenge mit PHPStan, Psalm und Rector, dazu PHPUnit für alles, was Typen nicht abdecken können. Für Frontend Projekte mit Astro ist der Typecheck bei uns kein Extra, sondern Teil der Definition of Done.

CYPRESS.IO Ambassador und IT Consultant für QA Engenieering und Qualität in PHP Projekten.

Frontend 2025: Optimieren Sie Ihre Webseite mit Astro JS und nutzen Sie die Vorteile der Barrierefreiheit

Optimieren Sie Ihre Webseite mit Astro JS und nutzen Sie die Vorteile einer schnellen, sicheren und barrierefreien Webseite. Erfüllen Sie die gesetzlichen Anforderungen und verbessern Sie die Benutzererfahrung Ihrer Webseite. Mit Astro JS können Sie die Ladezeit reduzieren, die Sicherheit maximieren und die SEO-Optimierung verbessern. Kontaktieren Sie uns, um mehr zu erfahren und um Ihre Webseite auf ein neues Level zu heben.

Astro JS Frontend E-Mail Kontakt

Häufige Fragen zum TypeScript never Type

Die wichtigsten Fragen aus Beratungsprojekten und Trainings rund um never, Exhaustive Checks und typsicheres KI Coding.

Was ist der never Type in TypeScript 2026?

never ist der Type für Werte, die niemals auftreten. Kein Wert lässt sich einer never Variable zuweisen, aber never selbst ist jedem Type zuweisbar. Der Compiler nutzt never für unerreichbare Codepfade und für Union Types, die durch Narrowing leergelaufen sind.

Wofür brauche ich never 2026 im Alltag?

Der wichtigste Fall ist der Exhaustive Check. Du behandelst alle Fälle eines Union Types in einem switch und lässt den Compiler prüfen, ob wirklich keiner fehlt. Kommt später ein Fall dazu, bricht der Build ab statt still undefined zu liefern.

Warum ist never 2026 beim KI Coding so wichtig?

KI Agents erweitern Union Types und vergessen die zugehörigen switch Stellen. Ohne Exhaustive Check kompiliert der Code trotzdem. Mit assertNever wird daraus ein harter Compilerfehler, den der Agent selbst liest und in derselben Session behebt.

Was ist der Unterschied zwischen never und void 2026?

Eine void Funktion läuft durch und gibt undefined zurück. Eine never Funktion kehrt nie zurück, weil sie wirft oder endlos läuft. void bedeutet kein interessanter Rückgabewert, never bedeutet gar kein Rückgabewert.

Wie schreibe ich 2026 eine assertNever Funktion?

Eine Funktion mit einem Parameter vom Typ never und Rückgabetyp never, die einen Fehler wirft. Im default Zweig eines switch aufgerufen, meldet der Compiler jeden nicht behandelten Fall der Union namentlich.

Was ist der Unterschied zwischen never und unknown?

unknown ist der Top Type: Jeder Wert passt hinein, aber du musst prüfen, bevor du ihn benutzt. never ist der Bottom Type: Kein Wert passt hinein. unknown nutzt du für fremde Daten, never für unmögliche Zustände.

Warum zeigt meine IDE plötzlich never an?

Meist wegen eines leeren Arrays ohne Typangabe, einer widersprüchlichen Intersection wie string und number, oder weil das Narrowing alle Möglichkeiten ausgeschlossen hat. Der erste Fall ist ein Fehler, der letzte ist gewollt.

Wie filtere ich Union Types mit never?

In Conditional Types verhält sich never wie die leere Menge. Ein Zweig, der never liefert, verschwindet aus dem Ergebnis. Genau so sind die eingebauten Utility Types Exclude und NonNullable definiert.

Funktioniert der Exhaustive Check auch mit Enums?

Ja. Enums verhalten sich wie Union Types aus Literalen. Der default Zweig mit assertNever meldet jeden nicht behandelten Enum Fall. Bei String Literal Unions ist das Verhalten identisch und in modernen Codebasen die häufigere Variante.

Brauche ich strict Mode für never?

never funktioniert auch ohne strict Mode, entfaltet seinen Nutzen aber erst mit strictNullChecks. Ohne strict laufen null und undefined durch jede Prüfung, und das Narrowing wird unzuverlässig. In neuen Projekten ist strict der Standard.

Wie erkenne ich fehlende Exhaustive Checks in einer alten Codebasis?

Suche nach switch Anweisungen über Union Types ohne default Zweig. Aktiviere zusätzlich noImplicitReturns, dann meldet der Compiler Funktionen, die nicht auf allen Pfaden zurückgeben. Danach ergänzt du assertNever Schritt für Schritt.

Gibt es ein Gegenstück zu never in PHP?

PHP kennt seit Version 8.1 einen eigenen never Rückgabetyp für Funktionen, die immer werfen oder das Skript beenden. Für die Vollständigkeitsprüfung von Fällen übernimmt in PHP der match Ausdruck zusammen mit PHPStan diese Rolle.

Kostet der Exhaustive Check Laufzeit?

Praktisch nicht. Der Compilerteil verschwindet beim Kompilieren komplett. Zur Laufzeit bleibt nur ein default Zweig, der im Normalfall nie erreicht wird. Der Fehler wird nur geworfen, wenn wirklich ein unbekannter Wert ankommt.

Wie bringe ich einem KI Agent never Regeln bei?

Über die Regeldatei des Agents, etwa CLAUDE.md. Dort steht als Regel: Jeder switch über einen Union Type endet mit assertNever, kein any, und tsc noEmit muss vor jedem Commit grün sein. Der Agent hält sich daran wie an eine Konfiguration.

Wo gehört der Typecheck in die Pipeline?

Als eigener Schritt, getrennt vom Build. Bundler wie Vite bauen auch bei kaputten Typen weiter. Erst ein separater tsc noEmit Schritt macht die Pipeline rot und verhindert, dass fehlerhafter Code in Production landet.