Булевый тип Boolean — самый компактный в JavaScript. Всего два значения: true и false. Литералы пишутся в нижнем регистре, без кавычек, и обычно появляются в логических выражениях:
let isLoggedIn = true;
let hasError = false;
let canSubmit = isLoggedIn && !hasError;
let isAdult = age >= 18;
let isOpen = element.classList.contains('open');
Несмотря на «всего два значения», булевый — один из самых частых типов в коде. Каждое if, каждый тернарник, каждый цикл по условию — всё построено на булевых. И именно поэтому конверсии «в булевое» и «из булевого» постоянно встречаются.
Зачем превращать булевое во что-то ещё
В чистом коде булевое живёт само в себе и нигде не пересекается с другими типами. Но как только начинаются эффекты во внешнем мире — начинаются преобразования.
- localStorage. Хранилище принимает только строки — localStorage.setItem('flag', true) положит туда "true", не true. При чтении нужно явно сравнивать с "true", иначе любая непустая строка превратится в true через прямой Boolean(x).
- API-форматы. Часть бэкендов вместо true/false ждёт 1/0 (наследие SQL и протоколов вроде MQTT). Перед отправкой делается Number(flag).
- HTML-атрибуты. aria-pressed, aria-expanded и подобные принимают именно строки "true"/"false". Прямое присвоение булевого в атрибут даёт ту же строку, но через String(flag) читается лучше.
- Арифметика над флагами. Считать «сколько чекбоксов отмечено» удобно через arr.filter(x => x).length, но иногда — через сложение: true + true + false === 2. Это уже автоматическое преобразование к числу.
- Сериализация и логи. При выводе в DOM или в консоль true отображается как строка "true" — JavaScript подставляет toString() сам.
Пять направлений преобразования
Из булевого можно получить любой другой тип. Большинство кейсов разбирается в отдельных главах — ниже короткий обзор, чтобы держать в голове общую картину.
- Булевое в строку — String(flag) или flag.toString(). Оба возвращают "true" или "false". Шаблонный литерал `${flag}` делает то же самое.
- Булевое в число — Number(true) === 1, Number(false) === 0. Унарный плюс +true делает то же. Удобно для подсчёта truthy-значений в массиве.
- Булевое в массив — [flag] просто оборачивает значение в одноэлементный массив. Семантически странный случай (чаще нужно «собрать массив флагов»), но иногда требуется для унификации интерфейса.
- Булевое в объект — new Boolean(flag) создаёт объект-обёртку. В современном коде почти не нужен — примитив сам «боксится», когда вызываешь у него метод. Один из редких случаев — интероп со старым кодом, ожидающим именно объект.
- Булевое в специальное значение — null, undefined, NaN. Делается тернарником, когда нужно «стереть» флаг.
Truthy и falsy — шесть значений на запоминание
В JavaScript любое значение можно использовать в условии: if (x). Движок сам неявно превратит его в булевое. Список falsy-значений строго определён — их шесть штук:
false // false
0, -0, 0n // false (ноль обычный, ноль отрицательный, ноль BigInt)
"" // false (пустая строка)
null // false
undefined // false
NaN // false
// всё остальное — truthy:
"false" // true (строка, не пустая)
"0" // true (всё ещё строка)
[] // true (пустой массив — объект, не пустота)
{} // true (пустой объект)
function() {} // true (функция)
Infinity, -Infinity // true
Самые контринтуитивные пункты — строки "false" и "0" (truthy) и пустые коллекции [], {} (тоже truthy, потому что это объекты). Из-за них прямой Boolean(x) не работает там, где значение пришло строкой из localStorage или URL.
!! — идиома короткого приведения
Стандартный способ превратить значение в булевое — Boolean(x). Но в коде гораздо чаще встречается короткая запись !!x — двойное логическое НЕ.
let user = { name: 'Сергей' };
// длинная запись
let hasUser = Boolean(user); // true
// короткая
let hasUser2 = !!user; // true
// внутри — два инвертирования: !user → false, !false → true
// если user = null: !null → true, !true → false
Оба варианта дают тот же результат. Boolean(x) предпочитают, когда читабельность важнее краткости (особенно в публичных функциях). !!x — в плотном коде, где привычка глаза уже сформирована. В TypeScript оба работают одинаково.
Подводные камни
Boolean("false") === true. Самая известная ловушка: любая непустая строка — truthy. Если из URL пришло ?active=false или из localStorage достали "false", — прямое преобразование вернёт true. Правильный способ — явное сравнение: x === "true". Или нормализация через JSON.parse(x) (она поймёт и "false", и "null", и числа).
Числа в булеве. Любое число, кроме нуля и NaN, truthy. Boolean(-1), Boolean(0.0001), Boolean(Infinity) — все true. Это полезно для проверок вида if (arr.length) — ноль элементов даст false, любое количество — true.
Boolean({}) и Boolean([]) всегда true. Объекты и массивы — не примитивы; для них логическое преобразование всегда даёт true. Если хочется «true только если есть что-то внутри», проверяй Object.keys(obj).length или arr.length.
Сравнение булевого через ==. true == 1 — true, true == "1" — тоже true, true == "true" — уже false (потому что строка "true" при сравнении с булевым превращается в число NaN). Чтобы избегать сюрпризов, используй строгое === или явно приводи оба значения к одному типу.
Объект-обёртка ведёт себя странно. new Boolean(false) — объект, а объект всегда truthy. Поэтому if (new Boolean(false)) попадает в if-ветку. Это одна из главных причин избегать конструктора без new — вызов Boolean(false) без new вернёт нормальное false.