Von allen Primitive-Typen ist boolean der konzeptionell einfachste: zwei Werte, true und false, mehr gibt es nicht. Spannend wird er trotzdem, sobald JavaScripts Truthy/Falsy-Semantik ins Spiel kommt — denn TypeScript verlässt sich in Conditions auf genau diese Coercion und nutzt sie aktiv für Truthiness-Narrowing. Dieser Artikel zeigt den Unterschied zwischen boolean und der Wrapper-Klasse Boolean, wann Literal-Types wie true und false sinnvoll sind, wie Boolean(x) und !!x zueinander stehen, warum arr.filter(Boolean) typseitig oft enttäuscht und wie ein sauberes Type Predicate dieses Problem behebt. Am Ende kennst du alle Stolperfallen rund um Wahrheitswerte — von ?? vs. || bis hin zu as const als Hebel für Literal-Typen.

boolean als Primitive

Der Typ boolean repräsentiert exakt zwei Werte: true und false. Er entspricht dem Ergebnis von typeof x === "boolean" und ist einer der drei Primitive-Typen, mit denen du in TypeScript am häufigsten arbeitest.

ts boolean-basics.ts
let isActive: boolean = true;
let isDone: boolean = false;

// Inferenz reicht meistens — Annotation hier eigentlich überflüssig:
let hasError = false; // Typ: boolean

Klein vs. Groß — boolean vs. Boolean:

In JavaScript existiert zusätzlich die Wrapper-Klasse Boolean. Sie erzeugt Objekte, keine Primitives, und ist in Type-Annotations praktisch immer falsch.

ts boolean-vs-Boolean.ts
// Primitive — richtig
const a: boolean = true;

// Wrapper-Objekt — fast immer falsch
const b: Boolean = new Boolean(true);

typeof a; // "boolean"
typeof b; // "object"  !

// Tückisch: ein Boolean-Objekt ist immer truthy — auch new Boolean(false)!
if (new Boolean(false)) {
    console.log("Wird ausgeführt — Objekt ist truthy.");
}

Faustregel: immer kleingeschriebenes boolean. Die großen Wrapper-Typen Boolean, Number, String sind technisch legal, in der Praxis aber ein Anti-Pattern.

Boolean-Literale als Typen

Wie bei string und number lassen sich auch einzelne true/false-Werte als Typen verwenden. Tatsächlich ist boolean intern nichts anderes als die Union true | false.

ts boolean-literals.ts
type Yes = true;
type No = false;

const ok: Yes = true;
// const nope: Yes = false; // − Type 'false' is not assignable to type 'true'.

// boolean ist eine Union:
type Bool = true | false; // identisch zu boolean

Warum überhaupt Boolean-Literale? Vor allem für Discriminated Unions mit binärem Schalter und für API-Flags, deren Verhalten sich vom Wert abhängig ändert.

ts boolean-literal-discriminator.ts
type SuccessResponse = {
    ok: true;
    data: string;
};

type ErrorResponse = {
    ok: false;
    error: string;
};

type ApiResponse = SuccessResponse | ErrorResponse;

function handle(res: ApiResponse) {
    if (res.ok) {
        // TS weiß: res ist SuccessResponse
        console.log(res.data.toUpperCase());
    } else {
        // TS weiß: res ist ErrorResponse
        console.error(res.error);
    }
}

as const für Literal-Typen:

Ohne as const wird ein literaler Boolean-Wert zu boolean geweitet, was Discriminator-Logik bricht.

ts boolean-as-const.ts
const wide = { ok: true, data: "hi" };
// wide.ok hat Typ boolean — nicht zuweisbar an SuccessResponse!

const narrow = { ok: true, data: "hi" } as const;
// narrow.ok hat Typ true — passt zu SuccessResponse.

const fn = (res: SuccessResponse) => res.data;
// fn(wide);   // −
fn(narrow);    // +

Truthy und Falsy in JavaScript/TypeScript

Jeder JavaScript-Wert kann in einer Boolean-Position (z. B. if (...)) implizit zu true oder false konvertiert werden. Die Falsy-Werte sind abschließend und kurz:

WertTruthy?
false− falsy
0, -0, 0n (BigInt-Null)− falsy
"" (leerer String)− falsy
null− falsy
undefined− falsy
NaN− falsy
alles andere+ truthy

Insbesondere sind diese Werte truthy, was häufig überrascht:

ts surprising-truthy.ts
if ([]) console.log("truthy");        // leeres Array → truthy
if ({}) console.log("truthy");        // leeres Objekt → truthy
if ("false") console.log("truthy");   // String "false" → truthy
if ("0") console.log("truthy");       // String "0"   → truthy
if (new Boolean(false)) console.log("truthy"); // Wrapper → truthy

Truthiness-Narrowing

TypeScript versteht Truthiness und verengt in if-Branches passende Union-Typen automatisch. Das ist eine der wichtigsten Narrowing-Mechaniken überhaupt.

ts truthiness-narrowing.ts
function greet(name: string | null) {
    if (name) {
        // Typ hier: string (null wurde herausgefiltert)
        console.log(name.toUpperCase());
    } else {
        // Typ hier: null
        console.log("Hallo, Unbekannter.");
    }
}

Achtung — Truthiness ist zu breit für string/number:

Ein leerer String und 0 sind ebenfalls falsy. Wenn du null/undefined ausschließen willst, prüfe explizit darauf.

ts truthiness-pitfall.ts
function lengthOf(s: string | null) {
    if (s) {
        return s.length; // funktioniert — aber: bei "" wird der Else-Branch genommen!
    }
    return 0;
}

// Sauberer:
function lengthOfStrict(s: string | null) {
    if (s !== null) {
        return s.length; // auch "" ergibt 0, nicht den Fallback.
    }
    return 0;
}

Aliased Conditions (TS 4.4+):

Seit TypeScript 4.4 funktioniert Truthiness-Narrowing auch für in Variablen zwischengespeicherte Bedingungen.

ts aliased-condition.ts
function process(value: string | null) {
    const hasValue = value !== null;
    if (hasValue) {
        // Seit TS 4.4: value ist hier string, nicht string | null.
        console.log(value.toUpperCase());
    }
}

Boolean(x) vs. !!x

Beide Ausdrücke konvertieren einen beliebigen Wert in einen echten Boolean. Funktional sind sie identisch — typeseitig gibt es einen feinen Unterschied.

ts boolean-conversion.ts
const x: unknown = "hallo";

const a = Boolean(x);  // Typ: boolean
const b = !!x;         // Typ: boolean (zur Laufzeit identisch)

// Konvertierungs-Beispiele:
Boolean(undefined); // false
Boolean(null);      // false
Boolean(0);         // false
Boolean(NaN);       // false
Boolean("");        // false
Boolean([]);        // true
Boolean({});        // true

Wichtig: Boolean(x) (Funktionsaufruf) ist nicht zu verwechseln mit new Boolean(x) (Konstruktor) — letzterer erzeugt ein Wrapper-Objekt und ist fast immer ein Bug.

Boolean als Filter-Funktion

Ein beliebtes Idiom zum Entfernen falsy Werte aus einem Array:

ts filter-boolean.ts
const raw = ["a", "", "b", null, "c", undefined, 0];
const cleaned = raw.filter(Boolean);
// Laufzeit: ["a", "b", "c"]

Aber: TypeScript verengt den Typ nicht automatisch. cleaned hat hier den Typ (string | number | null | undefined)[] — nicht string[]. Der Compiler weiß nichts von der semantischen Bedeutung des Filters.

ts filter-boolean-type-issue.ts
const items: (string | null | undefined)[] = ["a", null, "b"];
const filtered = items.filter(Boolean);
// filtered: (string | null | undefined)[] — nicht string[] −

filtered.forEach((s) => s.toUpperCase());
//                     ~ Object is possibly 'null' or 'undefined'.

Type Predicate für sauberes Filtern

Die Lösung: ein eigenes Type Predicate als Callback. Eine Funktion mit Rückgabetyp value is T teilt dem Compiler explizit mit, welcher Typ in der true-Branch übrig bleibt.

ts type-predicate-filter.ts
function isDefined<T>(value: T | null | undefined): value is T {
    return value !== null && value !== undefined;
}

const items: (string | null | undefined)[] = ["a", null, "b"];
const filtered = items.filter(isDefined);
// filtered: string[] +

filtered.forEach((s) => s.toUpperCase()); // kein Fehler

Alternativ — wenn du auch alle übrigen Falsy-Werte ("", 0, NaN) entfernen möchtest:

ts type-predicate-truthy.ts
function isTruthy<T>(value: T): value is Exclude<T, null | undefined | "" | 0 | false> {
    return Boolean(value);
}

const mixed = ["a", "", "b", null];
const truthy = mixed.filter(isTruthy);
// truthy: string[]

Boolean-Operatoren und Narrowing

&&, || und ?? evaluieren in JavaScript per Short-Circuit — und TypeScript narrowt entsprechend.

&& und ||:

ts and-or.ts
// && gibt den ersten falsy Wert zurück, sonst den letzten.
const a = "hallo" && 42;       // 42
const b = 0 && "hi";           // 0

// || gibt den ersten truthy Wert zurück, sonst den letzten.
const c = "" || "Default";     // "Default"
const d = 0 || "fallback";     // "fallback"  ! auch bei gewolltem 0!

?? (Nullish-Coalescing, TS 3.7+):

Im Unterschied zu || greift ?? nur bei null oder undefined0 und "" bleiben erhalten.

ts nullish-coalescing.ts
function getPort(input: number | null | undefined) {
    // Falsch — 0 würde überschrieben:
    const bad = input || 8080;

    // Richtig — nur null/undefined wird ersetzt:
    const good = input ?? 8080;

    return good;
}

getPort(0);         // 0
getPort(null);      // 8080
getPort(undefined); // 8080

Optional Chaining + Nullish-Coalescing:

ts optional-chain-nullish.ts
type User = { name?: string };

function displayName(u: User | null) {
    return u?.name ?? "Anonym";
}

displayName(null);                // "Anonym"
displayName({});                  // "Anonym"
displayName({ name: "" });        // ""  — leerer String bleibt!
displayName({ name: "Lina" });    // "Lina"

Interessantes

boolean vs. Boolean — kleinschreiben ist Pflicht.

boolean ist der Primitive-Typ und der einzige, den du in Annotations verwenden solltest. Boolean (groß) referenziert die Wrapper-Klasse — Instanzen davon sind Objekte und damit immer truthy, selbst new Boolean(false). Eine Quelle subtiler Bugs.

Klassische Falle — if (0) ist falsy.

Wenn du eine numerische Variable in einer Condition prüfst, fällt der Wert 0 in den falsy-Branch. Bei Mengen, Counts oder Indizes oft ungewollt. Lieber explizit if (n !== 0) oder if (n != null) verwenden.

?? vs. || — Nullish-Coalescing prüft nur null/undefined.

x || fallback springt bei jedem falsy-Wert ein (0, "", NaN usw.) — meist nicht gewollt. x ?? fallback ersetzt nur null und undefined. Verfügbar seit TypeScript 3.7.

arr.filter(Boolean) typt nicht ohne Predicate.

Zur Laufzeit entfernt das Idiom alle falsy Werte, aber der Compiler behält den ursprünglichen Element-Typ. Für korrekte Typen einen Type Guard wie (v): v is T => v !== null && v !== undefined verwenden.

Boolean(undefined) ergibt false — Standard-Konvertierung.

Sowohl Boolean() als auch !! folgen der ECMAScript-ToBoolean-Operation. Alle Falsy-Werte werden zu false, alle anderen zu true. Konsistent und deterministisch.

Truthy/Falsy stammen aus der JavaScript-Spec.

Die Begriffe beschreiben das Ergebnis der internen ToBoolean-Konvertierung. TypeScript erfindet hier nichts Neues — es nutzt nur das vorhandene JavaScript-Verhalten für sein Truthiness-Narrowing.

TS 4.4 — verbesserte Control-Flow-Analyse für aliased boolean conditions.

Vor 4.4 verlor TypeScript die Narrowing-Information, sobald du eine Bedingung in einer Variable zwischenspeichertest (const ok = x !== null; if (ok) ...). Seit 4.4 funktioniert das in einfachen Fällen — sauberer Code wird endlich belohnt.

as const macht true/false zu Literal-Typen.

Ohne as const wird ein Objekt mit ok: true auf { ok: boolean } geweitet, was Discriminated Unions kaputt macht. Mit as const bleibt der Typ exakt { readonly ok: true } erhalten — entscheidend für saubere Tag-Unions.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Primitive Typen

Zur Übersicht