Boolean ist mit nur zwei Werten — true und false — der einfachste Primitive-Typ. Trotzdem ist er Quelle für überraschend viele Bugs. Grund: JavaScript coerced in Boolean-Kontexten (if, while, &&, ||, !) jeden Wert automatisch zu Boolean. Genau 8 Werte zählen als falsy, alles andere ist truthy — auch leere Arrays, leere Objekte und der berüchtigte new Boolean(false)-Wrapper. Wer diese Liste nicht im Kopf hat, baut subtile Logik-Fehler. Dieser Artikel klärt die acht Falsy-Werte, die wichtigsten Truthy-Fallen und warum !!x der idiomatische Weg zum Boolean ist.
Zwei Werte, ein Primitive
Boolean ist mit nur zwei möglichen Ausprägungen — true und false — der minimalste Datentyp. Wie alle Primitives ist er immutable und wird per Wert verglichen.
const aktiv = true;
const sichtbar = false;
typeof aktiv; // 'boolean'
typeof false; // 'boolean'
// Vergleichs-Operatoren liefern Boolean
typeof (5 > 3); // 'boolean'
typeof !sichtbar; // 'boolean'
// Logische Operatoren liefern NICHT immer Boolean (siehe Section 7)
typeof ('a' || 'b'); // 'string' (!)boolean
boolean
stringDer Boolean-Kontext
Wann immer JavaScript einen Wert in einem Boolean-Kontext braucht — if, while, ternär ?:, &&, ||, !, Boolean(), !! — wird der Wert implizit zu true oder false coerced. Die Spezifikation legt genau acht Werte fest, die zu false coerced werden. Alles andere wird zu true.
Das Konzept ist mächtig — if (user) prüft elegant auf „existiert und ist gesetzt" — aber die genaue Liste muss im Kopf sitzen, sonst entstehen subtile Bugs.
// alle Boolean-Kontexte
if (wert) { /* … */ }
while (wert) { /* … */ }
wert ? 'a' : 'b';
wert && 'next';
wert || 'fallback';
!wert;
Boolean(wert);
!!wert;
// Beispiel: existiert die Antwort?
const response = fetchSync();
if (response) {
// truthy: response ist gesetzt UND nicht leer
}Vollständige Liste
Es gibt genau acht Werte, die in Boolean-Kontexten zu false werden. Diese Liste ist seit ES6 stabil — mit 0n (BigInt) wurde sie erweitert.
| Wert | Typ | Anmerkung |
|---|---|---|
false | Boolean | der Boolean selbst |
0 | Number | numerische Null (auch 0.0, 0x0) |
-0 | Number | negative Null — eigenes Bit-Muster |
0n | BigInt | BigInt-Null (seit ES2020) |
'' | String | leerer String (auch "" und ` `) |
null | Null | absichtliche Abwesenheit |
undefined | Undefined | nicht zugewiesen / Default-Parameter |
NaN | Number | Not-a-Number |
// alle 8 falsy
Boolean(false); // false
Boolean(0); // false
Boolean(-0); // false
Boolean(0n); // false
Boolean(''); // false
Boolean(null); // false
Boolean(undefined); // false
Boolean(NaN); // false
// Sonderfall: document.all (Legacy-DOM, im Browser)
// ist ebenfalls falsy — historischer Spec-HackfalseWas überraschend truthy ist
Die wichtigste Lehre aus der Falsy-Liste: alles andere ist truthy. Das umfasst einige Werte, die intuitiv „leer" oder „falsch" wirken.
// alle Objects sind truthy — auch wenn sie leer sind
Boolean([]); // true — leeres Array!
Boolean({}); // true — leeres Object!
Boolean(new Map()); // true
Boolean(new Date()); // true — auch Invalid Date
// Strings: Inhalt egal, nur Leerheit zählt
Boolean('0'); // true — String 'null' wäre auch truthy
Boolean('false'); // true
Boolean(' '); // true — Whitespace zählt!
// Numbers: nur Null und NaN sind falsy
Boolean(-1); // true
Boolean(Infinity); // true
Boolean(0.0001); // true
// Funktionen: immer truthy
Boolean(() => {}); // truetrue
true
trueExplizite Konvertierung
Es gibt zwei idiomatische Wege, einen beliebigen Wert zu Boolean zu coercen — beide funktional identisch.
// Variante 1: Boolean() als Funktion (NICHT mit new!)
Boolean('hi'); // true
Boolean(0); // false
Boolean([]); // true
// Variante 2: doppelte Negation — idiomatischer
!!'hi'; // true — !'hi' ist false, !!… ist true
!!0; // false
!![]; // true
// beide äquivalent — Wahl ist Stilfrage
// Linter wie ESLint erlauben meist beide
// praktischer Use-Case: API-Antwort zu sauberem Boolean
const hasItems = !!response?.items?.length;
const isLoggedIn = Boolean(user?.id);true
false
true!! ist kürzer und in der JavaScript-Community Standard, Boolean() ist expliziter und für Anfänger lesbarer. Wichtig: niemals new Boolean(value) — das erzeugt einen Object-Wrapper (siehe Section 8).
if (x) vs. if (x === true)
Implizites Boolean-Coercion in if-Statements ist Standard-Praxis. Der explizite Vergleich === true ist fast immer falsch — er prüft nicht „Wahrheit", sondern „ist exakt der Boolean true".
const flag = 1;
// implizit (idiomatisch)
if (flag) {
// läuft, weil 1 truthy ist
}
// explizit — wird NICHT eintreten!
if (flag === true) {
// läuft NICHT, weil 1 !== true (verschiedener Typ)
}
// sinnvoll: wenn API garantiert nur Boolean zurückgibt
const isAdmin = checkAdmin(); // gibt streng Boolean zurück
if (isAdmin === true) {
// okay als Type-Guard / API-Contract-Check
}
// mit ?: für Fallback-Werte
const name = user.name || 'Anonym'; // Fallback bei falsy
const safe = user.name ?? 'Anonym'; // Fallback nur bei null/undefinedShort-Circuit gibt den Operanden zurück
Eine der wichtigsten Eigenheiten von && und || in JavaScript: sie geben nicht immer einen Boolean zurück, sondern den letzten ausgewerteten Operanden. Dieses Verhalten ist ES1-alt und wird konstant für Defaults und Guards eingesetzt.
// || gibt ersten truthy zurück, sonst letzten Wert
'a' || 'b'; // 'a'
'' || 'b'; // 'b'
0 || null || 'x'; // 'x'
0 || null; // null — letzter Wert, alle falsy
// && gibt ersten falsy zurück, sonst letzten Wert
'a' && 'b'; // 'b'
'' && 'b'; // ''
true && null; // null
true && 'x' && 5; // 5
// praktischer Einsatz: Default-Wert
const port = config.port || 3000;
// ABER: bei port=0 würde der Fallback ungewollt greifen!
// ?? statt || für "nur null/undefined als leer"
const port2 = config.port ?? 3000; // nur fallback bei null/undefineda
b
xnew Boolean(false) ist truthy
Die wahrscheinlich berüchtigtste JavaScript-Falle. Wie alle Primitives hat Boolean einen Object-Wrapper — new Boolean(value). Das Resultat ist ein Object, und alle Objects sind truthy. Auch der Wrapper um false.
const wrapper = new Boolean(false);
typeof wrapper; // 'object' (!)
wrapper === false; // false
wrapper.valueOf(); // false — der innere Wert ist false
// aber im Boolean-Kontext: TRUTHY!
if (wrapper) {
console.log('Das läuft!'); // wird ausgeführt
}
Boolean(wrapper); // true — alle Objects sind truthy
// Boolean() OHNE new ist die korrekte Coercion
Boolean(false); // false — gut
new Boolean(false); // Object — schlecht
// gleiche Falle wie new String(''), new Number(0)object
Das läuft!In über 25 Jahren JavaScript hat dieses Pattern keinen einzigen sinnvollen Use-Case gefunden — der Wrapper-Konstruktor ist heute nur noch Spec-Altlast. Linter wie ESLint warnen mit der Regel no-new-wrappers.
Wann === true sinnvoll ist
Trotz der Faustregel „immer implizit prüfen" gibt es Fälle, in denen === true die richtige Wahl ist — nämlich dort, wo das API-Contract garantiert nur Boolean liefern soll und ein anderer Wert ein Bug-Indikator wäre.
// Type-Guard: prüfen, ob der Wert wirklich Boolean ist
function istEchterBoolean(x) {
return typeof x === 'boolean';
}
// API-Contract: Funktion soll garantiert Boolean liefern
function isValid(input) {
// … Logik …
return result === true; // nur exakt true zählt
}
// bei Drittanbieter-API, wo "truthy" nicht reicht
if (response.success === true) {
// unterscheidet zwischen 1, 'ok', {…} und echtem Boolean
}
// praktisch: Filter-Predicates
[true, 1, 'true', null].filter(x => x === true); // [true]
[true, 1, 'true', null].filter(Boolean); // [true, 1, 'true'][ true ]In TypeScript-Codebasen ist === true seltener nötig, weil der Compiler den Typ ohnehin zu Boolean engt. In Vanilla-JS ist es ein nützliches Werkzeug für defensive Validierung.
Typische Fallen mit Truthy/Falsy
new Boolean(false) ist TRUTHY — der Klassiker
Der Object-Wrapper ist immer truthy, auch wenn er false umschließt. if (new Boolean(false)) läuft in den then-Zweig. Das gleiche Muster gilt für new String('') und new Number(0). Lehre: Boolean(value) als Funktion aufrufen, niemals mit new. Linter-Regel: no-new-wrappers.
Leeres Array [] ist TRUTHY
Alle Objects sind truthy, und Arrays sind Objects — auch wenn sie leer sind. if (arr) sagt also nur „arr existiert", nicht „arr enthält etwas". Korrekt: if (arr.length > 0) oder if (arr?.length). Gleiche Falle bei , new Map() und new Set().
'0' ist TRUTHY (String), 0 ist FALSY (Number)
Form-Inputs kommen aus dem DOM immer als String. Ein Eingabefeld mit Wert '0' ist truthy, der numerische Wert 0 nach parseInt wäre falsy. Das ist eine der häufigsten Quellen für „funktioniert lokal, aber nicht im Prod"-Bugs. Lösung: vor dem Test in den richtigen Typ konvertieren.
NaN ist FALSY — und nie gleich sich selbst
Boolean(NaN) ist false, aber NaN === NaN ist ebenfalls false. Wer auf NaN prüfen will, kann nicht x === NaN schreiben — das ist immer false. Korrekt: Number.isNaN(x). Für Boolean-Kontexte ist das Verhalten konsistent: NaN wirkt wie „leer".
?? berücksichtigt nur null und undefined als "leer"
Der Nullish-Coalescing-Operator ?? ist nicht dasselbe wie ||. 0 || 'fallback' ergibt 'fallback', 0 ?? 'fallback' ergibt 0. Wichtig bei numerischen oder Boolean-Defaults, bei denen 0, '' oder false gültige Werte sind. Mit || würden sie ungewollt überschrieben.
!!x ist idiomatischer als Boolean(x)
Beide sind funktional identisch und beide vom Linter erlaubt. !! ist in der JS-Community Standard, kürzer und in einer Expression-Position lesbarer (const has = !!list.length). Boolean() ist für Anfänger expliziter. Wichtig nur: niemals new Boolean().
if (obj) prüft Existenz, nicht Inhalt
if (response) sagt nur „response ist nicht null/undefined/0/leer-String". Es sagt nichts darüber, ob die Antwort sinnvoll ist. if (response.success) ist eine separate Prüfung — und wenn response selbst undefined wäre, würde die Property-Lese einen TypeError werfen. Optional Chaining (response?.success) löst das elegant.
Date-Objekte sind IMMER truthy — auch Invalid-Date
new Date('foo') erzeugt einen Invalid Date — das Object existiert, ist aber im Inneren NaN. Trotzdem ist es als Object truthy: Boolean(new Date('foo')) ist true. Wer auf Validität prüfen will: !Number.isNaN(date.getTime()) oder date instanceof Date && !isNaN(date).