EnglishGitHub
teilweisepackages/assert/src

Assert

@ralphschuler/assert

Prüft Laufzeitbedingungen mit dazu passendem TypeScript-Narrowing.

type narrowinginvariantserrors

01 · Problem

Wofür braucht man das?

Statische Typen schützen nicht vor Daten aus JSON, Netzwerk oder falsch aufgerufenen APIs. Kritische Invarianten müssen an der Systemgrenze zur Laufzeit erzwungen werden.

02 · Denkmodell

Das mentale Modell

Eine Assertion ist ein Gate: Hinter ihr darf der Rest des Programms von einer nachweislich erfüllten Bedingung ausgehen, andernfalls endet der Pfad mit einem klaren Fehler.

Im Repository

Prüft Laufzeitbedingungen mit dazu passendem TypeScript-Narrowing. Assertions werfen synchron; verschachtelte Schemas und asynchrone Reject-Prüfungen sind eigene Erweiterungen.

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. Unbekannten Wert an einer klaren Eingangsgrenze empfangen.
  2. Genau eine überprüfbare Bedingung auswerten.
  3. Bei Fehlschlag einen spezifischen AssertionError mit Kontext werfen.
  4. Bei Erfolg den Typ für nachfolgenden Code verengen.

04 · Bauteile

Die entscheidenden Verträge

assert / isString / isNumberPrüft Laufzeitbedingungen und verengt Typen.
isDefined / isNotNullSchließt genau undefined beziehungsweise null aus.
throws / AssertionErrorPrüft synchrones Werfen mit unterscheidbarem Fehlertyp.

05 · Selbst bauen

Selbst implementieren

Beginne mit einem korrekten Basistor und ergänze nur Assertions, deren Runtime-Prüfung exakt zur Type-Narrowing-Aussage passt.

  1. Implementiere assert mit einer asserts-condition-Signatur.
  2. Gib jeder spezialisierten Prüfung eine präzise Fehlermeldung und einen passenden Narrowing-Typ.
  3. Teste positive und negative Pfade getrennt; fange niemals den eigenen AssertionError versehentlich ab.
Konzeptskizze · kann ausgelassene Helfer verwenden
class AssertionError extends Error {}

function assert(value: unknown, message = "Assertion failed"): asserts value {
  if (!value) throw new AssertionError(message);
}

function isDefined<T>(value: T): asserts value is Exclude<T, undefined> {
  assert(value !== undefined, "Expected a defined value");
}

function throws(action: () => unknown) {
  let didThrow = false;
  try { action(); } catch { didThrow = true; }
  assert(didThrow, "Expected action to throw");
}

06 · Verifizieren

Was solltest du testen?

  • Jede Assertion besteht für gültige Werte und wirft den erwarteten Fehlertyp für ungültige.
  • NaN, Infinity, null und undefined werden entsprechend des dokumentierten Vertrags behandelt.
  • throws und eine optionale rejects-Variante schlagen zuverlässig beim falschen Kontrollfluss fehl.

Selbst ausprobieren

Formuliere die erste Prüfaussage als fehlschlagenden Test, implementiere die kleinste Korrektur und ergänze einen Grenzfall.

Jede Assertion besteht für gültige Werte und wirft den erwarteten Fehlertyp für ungültige.

Ansatz vergleichen

Dein Test sollte beim gezielten Verletzen der Invariante fehlschlagen und nach der Korrektur wieder bestehen. Halte den Aufbau deterministisch und prüfe ein beobachtbares Ergebnis.

07 · Grenzen

Kompromisse und Stolperfallen

  • Assertions werfen synchron; für erwartbare Validierungsfehler kann ein Result-Typ geeigneter sein.
  • Zu allgemeine Assertions verschleiern den eigentlichen Eingabevertrag.
  • Strukturelle Objektvalidierung benötigt Pfadkontext und meist ein Schema statt vieler Einzelprüfungen.
Wichtig

Assertions werfen synchron; verschachtelte Schemas und asynchrone Reject-Prüfungen sind eigene Erweiterungen.

08 · Weiterdenken

Quellcode und verwandte Ideen

yarn tsx packages/assert/examples/basic.ts