Модуль 2 · урок 10 з 15
Strict TypeScript
Тут починається друга половина модуля — TypeScript. Вимога ліда звучить жорстко:
strict-режим і рівно нуль any. Це не про суворість заради суворості: strict змушує
відповісти на питання «а що, як тут порожньо?» під час написання коду, а не в проді.
Що вмикає strict
Один прапорець "strict": true — це група перевірок. Найважливіші три:
| Перевірка | Що ловить |
|---|---|
strictNullChecks | null і undefined більше не входять у кожен тип — їх треба вказати явно й обробити |
noImplicitAny | Параметр без типу, який TypeScript не зміг вивести, стає помилкою, а не мовчазним any |
strictFunctionTypes | Несумісні сигнатури колбеків |
strictPropertyInitialization | Поле класу, яке ніколи не отримає значення |
strictNullChecks на прикладі
// без strict: типи брешуть
function greet(user: User) {
return 'Привіт, ' + user.name; // впаде, якщо прийде null — але компілятор мовчить
}
// зі strict: тип чесний
function greet(user: User | null) {
if (!user) return 'Привіт, гостю'; // компілятор ЗМУСИТЬ це написати
return 'Привіт, ' + user.name; // тут TS уже знає, що user не null
}
Останній рядок — це звуження типу: після перевірки TypeScript сам розуміє, що
всередині user точно є. Ніяких зайвих перевірок писати не треба.
Інструменти для роботи з порожнечею
user?.address?.city // undefined замість помилки
user.getName?.() // виклик, лише якщо метод існує
list?.[0] // безпечний доступ до елемента
const name = user.name ?? 'Гість'; // підставити, лише якщо null або undefined
const name = user.name || 'Гість'; // ⚠️ спрацює ще й на '' та 0
// раннє повернення читається краще, ніж вкладені if
function total(order: Order | null): number {
if (!order) return 0;
if (!order.items.length) return 0;
return order.items.reduce((s, i) => s + i.price, 0);
}
Знак оклику: коли можна, а коли це борг
const el = document.querySelector('.btn')!; // «я гарантую, що не null»
! вимикає перевірку в одному місці. Інколи це чесно — наприклад, ти щойно сам
створив цей елемент. Але частіше це спосіб замовчати проблему: якщо гарантія виявиться хибною,
впаде рантайм, а компілятор уже нічого не скаже.
// краще так: обробити відсутність явно
const el = document.querySelector<HTMLButtonElement>('.btn');
if (!el) return;
@Input() task!: Task; — тут ! означає «значення прийде ззовні,
до першого рендеру Angular його підставить». Це домовленість фреймворку, а не приховування
проблеми. У сигнальному стилі вона зникає сама: input.required<Task>()
гарантує наявність на рівні типів, і знак оклику не потрібен.
strictTemplates: перевірка типів у шаблонах
@Component({
template: `<app-task-card [task]="taskId()" />`, // ❌ передали string, а чекають Task
})
Без strictTemplates шаблон — сліпа зона: помилка виявиться в рантаймі як
undefined is not an object. З ним — це помилка компіляції з нормальним поясненням.
Прапорець уже стоїть у нових проєктах; головне не вимкнути його, коли щось «не збирається».
Кілька додаткових прапорців, які варто ввімкнути
{
"compilerOptions": {
"noUnusedLocals": true, // невикористані змінні — помилка
"noImplicitReturns": true, // функція має повертати значення на всіх шляхах
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true // відрізняє «поля немає» від «поле = undefined»
}
}
- Уточнити тип:
User | nullзамістьUser. - Додати перевірку й ранній вихід.
- Змінити модель так, щоб неможливий стан не виражався типом.
- Написати type guard (наступні уроки).
as any— валить збірку через ESLint.!без реальної гарантії.// @ts-ignore— те саме, тільки гірше видно.- Вимкнути strict «поки що».
Приблизно половина рантайм-помилок у фронтенді — це «читаю поле в чогось, чого немає». Strict перетворює цей клас помилок на помилки компіляції. Тобто ти платиш кількома хвилинами роздумів під час написання коду й не платиш годиною дебагу в проді.