В JavaScript null и undefined можно присвоить любой переменной. Это приводит к «ошибке на миллиард долларов» — TypeError: Cannot read property of null.
// В обычном JS это допустимо:
let user = getUser() // может вернуть null
user.name // TypeError если user === null!Когда в tsconfig.json включена опция strictNullChecks: true (по умолчанию в strict режиме), TypeScript считает null и undefined **отдельными типами**:
// strictNullChecks: false (старое поведение, не рекомендуется)
let name: string = null // OK
let age: number = undefined // OK
// strictNullChecks: true (рекомендуется)
let name: string = null // Ошибка: null не assignable to string
let age: number = undefined // Ошибка: undefined не assignable to number
// Явное объявление nullable типа:
let name: string | null = null // OK
let age: number | undefined = undefined // OKОператор ?. позволяет безопасно обращаться к свойствам, которые могут быть null или undefined. Если цепочка прерывается — возвращается undefined вместо ошибки.
interface User {
name: string
address?: {
city?: string
zip?: string
}
}
const user: User | null = getUser()
// Без optional chaining — опасно:
const city = user.address.city // Ошибка если user или address === null
// С optional chaining — безопасно:
const city = user?.address?.city // undefined если user или address null/undefined
// Работает и с методами:
const upperName = user?.name?.toUpperCase()
// И с массивами:
const firstItem = arr?.[0]Оператор ?? возвращает правый операнд только если левый равен null или undefined. В отличие от ||, не считает 0, "" или false «отсутствующими» значениями.
const name = user?.name ?? 'Аноним'
// Если user?.name === null или undefined — вернёт 'Аноним'
// Если user?.name === '' — вернёт '' (пустая строка — валидное значение!)
// Сравнение с ||:
const count1 = 0 || 10 // 10 — нежелательно! 0 — валидное число
const count2 = 0 ?? 10 // 0 — корректноОператор ! в конце выражения говорит TypeScript: «я гарантирую что это значение не null и не undefined». Используй с осторожностью — TypeScript тебе поверит.
const element = document.getElementById('app')
// element: HTMLElement | null
element.style.color = 'red' // Ошибка TS: Object is possibly null
element!.style.color = 'red' // OK — мы гарантируем что элемент существует
// Лучше: явная проверка
if (element) {
element.style.color = 'red' // OK — TypeScript сам сузит тип до HTMLElement
}function getLength(str: string | null): number {
// Вариант 1: if-проверка
if (str === null) {
return 0
}
return str.length // TS знает: str: string здесь
// Вариант 2: оператор ??
return (str ?? '').length
// Вариант 3: short-circuit
return str?.length ?? 0
}Безопасная работа с null и undefined: optional chaining, nullish coalescing, проверки
// Симуляция данных из API (могут быть null/undefined)
const users = [
{ id: 1, name: 'Алексей', address: { city: 'Москва', zip: '101000' } },
{ id: 2, name: 'Мария', address: null },
{ id: 3, name: null, address: { city: 'Казань' } },
null,
]
function findUser(id) {
return users[id - 1] // может вернуть null
}
// === Optional chaining ?. ===
console.log('=== Optional chaining ===')
const user1 = findUser(1)
const user4 = findUser(4) // null
// Без optional chaining — опасно:
// console.log(user4.name) // TypeError: Cannot read properties of null
// С optional chaining — безопасно:
console.log(user1?.name) // 'Алексей'
console.log(user1?.address?.city) // 'Москва'
console.log(user4?.name) // undefined (нет ошибки!)
console.log(findUser(2)?.address?.city) // undefined (address === null)
// === Nullish coalescing ?? ===
console.log('\n=== Nullish coalescing ?? ===')
function getUserCity(userId) {
const user = findUser(userId)
// ?. + ?? — безопасное получение с дефолтным значением
return user?.address?.city ?? 'Неизвестный город'
}
console.log(getUserCity(1)) // 'Москва'
console.log(getUserCity(2)) // 'Неизвестный город' (address === null)
console.log(getUserCity(4)) // 'Неизвестный город' (user === null)
// Разница ?? и ||:
const score = 0
console.log(score || 'нет данных') // 'нет данных' — НЕПРАВИЛЬНО для 0!
console.log(score ?? 'нет данных') // 0 — ПРАВИЛЬНО
const label = ''
console.log(label || 'без названия') // 'без названия' — может быть нежелательно
console.log(label ?? 'без названия') // '' — пустая строка сохраняется
// === Сужение null (narrowing) ===
console.log('\n=== Проверка null перед использованием ===')
function formatName(name) {
// Явная проверка на null/undefined (как TS narrowing)
if (name == null) { // == null ловит и null и undefined
return 'Имя не указано'
}
return name.toUpperCase() // здесь name точно строка
}
console.log(formatName('алексей')) // 'АЛЕКСЕЙ'
console.log(formatName(null)) // 'Имя не указано'
console.log(formatName(undefined)) // 'Имя не указано'
// Получение имён всех пользователей с фильтрацией null:
const names = users
.filter(u => u != null)
.map(u => u?.name ?? 'Аноним')
console.log('\nИмена пользователей:', names) // ['Алексей', 'Мария', 'Аноним']В JavaScript null и undefined можно присвоить любой переменной. Это приводит к «ошибке на миллиард долларов» — TypeError: Cannot read property of null.
// В обычном JS это допустимо:
let user = getUser() // может вернуть null
user.name // TypeError если user === null!Когда в tsconfig.json включена опция strictNullChecks: true (по умолчанию в strict режиме), TypeScript считает null и undefined **отдельными типами**:
// strictNullChecks: false (старое поведение, не рекомендуется)
let name: string = null // OK
let age: number = undefined // OK
// strictNullChecks: true (рекомендуется)
let name: string = null // Ошибка: null не assignable to string
let age: number = undefined // Ошибка: undefined не assignable to number
// Явное объявление nullable типа:
let name: string | null = null // OK
let age: number | undefined = undefined // OKОператор ?. позволяет безопасно обращаться к свойствам, которые могут быть null или undefined. Если цепочка прерывается — возвращается undefined вместо ошибки.
interface User {
name: string
address?: {
city?: string
zip?: string
}
}
const user: User | null = getUser()
// Без optional chaining — опасно:
const city = user.address.city // Ошибка если user или address === null
// С optional chaining — безопасно:
const city = user?.address?.city // undefined если user или address null/undefined
// Работает и с методами:
const upperName = user?.name?.toUpperCase()
// И с массивами:
const firstItem = arr?.[0]Оператор ?? возвращает правый операнд только если левый равен null или undefined. В отличие от ||, не считает 0, "" или false «отсутствующими» значениями.
const name = user?.name ?? 'Аноним'
// Если user?.name === null или undefined — вернёт 'Аноним'
// Если user?.name === '' — вернёт '' (пустая строка — валидное значение!)
// Сравнение с ||:
const count1 = 0 || 10 // 10 — нежелательно! 0 — валидное число
const count2 = 0 ?? 10 // 0 — корректноОператор ! в конце выражения говорит TypeScript: «я гарантирую что это значение не null и не undefined». Используй с осторожностью — TypeScript тебе поверит.
const element = document.getElementById('app')
// element: HTMLElement | null
element.style.color = 'red' // Ошибка TS: Object is possibly null
element!.style.color = 'red' // OK — мы гарантируем что элемент существует
// Лучше: явная проверка
if (element) {
element.style.color = 'red' // OK — TypeScript сам сузит тип до HTMLElement
}function getLength(str: string | null): number {
// Вариант 1: if-проверка
if (str === null) {
return 0
}
return str.length // TS знает: str: string здесь
// Вариант 2: оператор ??
return (str ?? '').length
// Вариант 3: short-circuit
return str?.length ?? 0
}Безопасная работа с null и undefined: optional chaining, nullish coalescing, проверки
// Симуляция данных из API (могут быть null/undefined)
const users = [
{ id: 1, name: 'Алексей', address: { city: 'Москва', zip: '101000' } },
{ id: 2, name: 'Мария', address: null },
{ id: 3, name: null, address: { city: 'Казань' } },
null,
]
function findUser(id) {
return users[id - 1] // может вернуть null
}
// === Optional chaining ?. ===
console.log('=== Optional chaining ===')
const user1 = findUser(1)
const user4 = findUser(4) // null
// Без optional chaining — опасно:
// console.log(user4.name) // TypeError: Cannot read properties of null
// С optional chaining — безопасно:
console.log(user1?.name) // 'Алексей'
console.log(user1?.address?.city) // 'Москва'
console.log(user4?.name) // undefined (нет ошибки!)
console.log(findUser(2)?.address?.city) // undefined (address === null)
// === Nullish coalescing ?? ===
console.log('\n=== Nullish coalescing ?? ===')
function getUserCity(userId) {
const user = findUser(userId)
// ?. + ?? — безопасное получение с дефолтным значением
return user?.address?.city ?? 'Неизвестный город'
}
console.log(getUserCity(1)) // 'Москва'
console.log(getUserCity(2)) // 'Неизвестный город' (address === null)
console.log(getUserCity(4)) // 'Неизвестный город' (user === null)
// Разница ?? и ||:
const score = 0
console.log(score || 'нет данных') // 'нет данных' — НЕПРАВИЛЬНО для 0!
console.log(score ?? 'нет данных') // 0 — ПРАВИЛЬНО
const label = ''
console.log(label || 'без названия') // 'без названия' — может быть нежелательно
console.log(label ?? 'без названия') // '' — пустая строка сохраняется
// === Сужение null (narrowing) ===
console.log('\n=== Проверка null перед использованием ===')
function formatName(name) {
// Явная проверка на null/undefined (как TS narrowing)
if (name == null) { // == null ловит и null и undefined
return 'Имя не указано'
}
return name.toUpperCase() // здесь name точно строка
}
console.log(formatName('алексей')) // 'АЛЕКСЕЙ'
console.log(formatName(null)) // 'Имя не указано'
console.log(formatName(undefined)) // 'Имя не указано'
// Получение имён всех пользователей с фильтрацией null:
const names = users
.filter(u => u != null)
.map(u => u?.name ?? 'Аноним')
console.log('\nИмена пользователей:', names) // ['Алексей', 'Мария', 'Аноним']Реализуй функцию `getUserInfo(user)`, которая принимает объект пользователя (или null) и возвращает строку с информацией. Если user — null, вернуть "Гость". Если user.name — null/undefined, использовать "Аноним". Если user.age — null/undefined, использовать "возраст неизвестен". Формат: "<name>, <age> лет" или "<name>, возраст неизвестен".
Для проверки на null и undefined используй == null (двойное равно ловит оба случая). Или используй оператор ??: name = user.name ?? "Аноним". Для age: если user.age != null, включай в строку, иначе пиши "возраст неизвестен".
Токены для AI-помощника закончились
Купи токены чтобы задавать вопросы AI прямо в уроке