Введение: Почему «просто if (value)» может вас подвести?
Каждый разработчик, переходящий с JavaScript на TypeScript, рано или поздно сталкивается с вопросом: «Is there a way to check for both null and undefined?». Этот вопрос набрал тысячи просмотров на Stack Overflow — и неспроста. На первый взгляд, задача кажется тривиальной: написать if (value != null) или if (value). Но дьявол, как всегда, кроется в деталях.
В этой статье мы разберём топ ошибок, которые допускают новички (и не только) при проверке на null и undefined в TypeScript. Вы узнаете, почему нестрогое сравнение может быть опаснее, чем кажется, как работает оператор Nullish Coalescing (??) и когда стоит использовать пользовательские защиты типов. Поехали!
Ошибка №1: Использование if (!value) для всех ложных значений
Самый распространённый антипаттерн — это попытка проверить наличие значения через отрицание:
// ❌ Плохо
function processInput(input: string | null | undefined) {
if (!input) {
console.log('Ввод отсутствует');
return;
}
console.log(input.toUpperCase());
}
processInput(''); // ❌ Выведет "Ввод отсутствует", хотя строка пустая, но НЕ null и НЕ undefined
Проблема в том, что !value преобразует любое ложное значение в true. В TypeScript (и JavaScript) ложными считаются: false, 0, '' (пустая строка), NaN, null, undefined. Если ваша бизнес-логика допускает пустую строку или число 0, такой код сломается.
Как избежать: Используйте строгую проверку на null и undefined через === или !==.
Ошибка №2: Слепое доверие value == null
Многие разработчики знают, что value == null (двойное равно) проверяет и null, и undefined одновременно. Это действительно работает:
// ✅ Работает, но...
function check(value: string | null | undefined) {
if (value == null) {
console.log('value is null or undefined');
}
}
Однако двойное равно в TypeScript — это источник неочевидных багов. Например, null == undefined — это true, но null == false — это false. А что насчёт '' == false? Тоже true. Нестрогое сравнение может вести себя непредсказуемо, особенно в сложных условиях.
Как избежать: В TypeScript value == null — это официально разрешённый паттерн (линтер часто его допускает), но для новичков лучше придерживаться явного подхода: value === null || value === undefined.
Ошибка №3: Игнорирование undefined при работе с объектами
Иногда разработчики проверяют только null, забывая про undefined:
// ❌ Опасно
interface User {
name?: string;
age: number | null;
}
function greet(user: User) {
if (user.age !== null) {
console.log(`Age: ${user.age}`);
}
// Если age не передан (undefined), код выполнится!
}
greet({ name: 'Alice' }); // Выведет "Age: undefined"
Поле age может быть null, number или undefined (если не указано в интерфейсе). Проверка только на null пропускает undefined.
Как избежать: Всегда проверяйте оба значения, если тип допускает оба. Или используйте оператор Optional Chaining (?.) и Nullish Coalescing (??).
Лучший способ: Строгая проверка с помощью ===
Самый надёжный и очевидный способ — явно сравнить с null и undefined:
// ✅ Отлично
function isNullOrUndefined(value: unknown): value is null | undefined {
return value === null || value === undefined;
}
// Использование
function display(value: string | null | undefined) {
if (isNullOrUndefined(value)) {
console.log('Значение отсутствует');
} else {
console.log(value);
}
}
Этот код работает предсказуемо и не зависит от ложных значений. Кроме того, мы использовали предикат типа (value is null | undefined), что позволяет TypeScript сузить тип в блоке if.
Профессиональный подход: Nullish Coalescing (??) и Optional Chaining
TypeScript (и современный JavaScript) предлагает два элегантных оператора для работы с null и undefined:
- Optional Chaining (
?.) — безопасный доступ к свойствам. Если значениеnullилиundefined, цепочка прерывается и возвращаетсяundefined. - Nullish Coalescing (
??) — возвращает правую часть, только если левая —nullилиundefined(в отличие от||, который реагирует на все ложные значения).
// Пример с Optional Chaining
interface Config {
theme?: {
color?: string;
};
}
const config: Config = {};
const color = config.theme?.color ?? 'blue'; // 'blue', так как theme undefined
console.log(color); // blue
// Пример с Nullish Coalescing
const count = 0;
const displayCount = count ?? 10; // 0, потому что 0 — не null и не undefined
const displayCountFallback = count || 10; // 10, потому что 0 — ложное значение!
console.log(displayCount); // 0
console.log(displayCountFallback); // 10
Этот подход особенно полезен при работе с API, где поля могут отсутствовать.
Пользовательская защита типа (Type Guard)
Если вам нужно часто проверять на null и undefined, создайте свою функцию-утилиту:
// Кастомный type guard
function isNil(value: unknown): value is null | undefined {
return value == null; // Здесь двойное равно уместно, но можно и ===
}
// Использование
function process(value: string | null | undefined) {
if (isNil(value)) {
// TypeScript знает, что value — null | undefined
return;
}
// Здесь value — string
console.log(value.length);
}
Такой подход делает код чище и переиспользуемым. Многие библиотеки (например, Lodash) имеют функцию isNil, но вы легко можете написать свою.