Пошук уроків, статей та іншого контенту
Увімкнете strict і розглянете параметри, що посилюють перевірку типів та зменшують кількість помилок під час виконання.
TypeScript за замовчуванням не вмикає всі найсуворіші перевірки. Деякі конструкції можуть компілюватися, навіть якщо потенційно призведуть до помилки під час виконання.
Strict mode — це набір налаштувань TypeScript, які роблять перевірку типів суворішою. Він допомагає знаходити помилки ще під час компіляції, а не після запуску програми.
Увімкнути всі основні суворі перевірки можна однією опцією:
{
"compilerOptions": {
"strict": true
}
}Після цього TypeScript перевірятиме код за суворішими правилами.
tsconfig.jsonСтворимо простий файл конфігурації:
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"strict": true,
"outDir": "dist"
},
"include": ["src"]
}target визначає версію JavaScript, у яку компілюється TypeScript.
module визначає формат модулів.
strict: true вмикає сувору перевірку типів.
outDir визначає папку для скомпільованих файлів.
include вказує, які файли потрібно перевіряти.
Скомпілювати проєкт можна командою:
npx tscПеревірити код без створення JavaScript-файлів:
npx tsc --noEmitОпція strict: true вмикає групу окремих параметрів. Кожен із них відповідає за певний вид перевірки.
noImplicitAnyЗабороняє неявний тип any.
Тип any вимикає більшість перевірок TypeScript. Якщо параметр функції не має типу і TypeScript не може його визначити, суворий режим покаже помилку.
function greet(name) {
return `Привіт, ${name}`;
}За strict: true TypeScript повідомить, що параметр name має неявний тип any.
Потрібно явно вказати тип:
function greet(name: string): string {
return `Привіт, ${name}`;
}
console.log(greet("Олена"));Це робить контракт функції зрозумілим: вона приймає рядок і повертає рядок.
strictNullChecksБез суворої перевірки null і undefined можуть непомітно використовуватися там, де очікується звичайне значення.
Наприклад:
function getUserName(): string {
const name: string | undefined = undefined;
return name;
}За strictNullChecks виникне помилка, тому що функція має повернути string, але змінна може містити undefined.
Потрібно спочатку перевірити значення:
function getUserName(): string {
const name: string | undefined = undefined;
if (name === undefined) {
return "Невідомий користувач";
}
return name;
}
console.log(getUserName());Або можна використати значення за замовчуванням:
function getUserName(name?: string): string {
return name ?? "Невідомий користувач";
}
console.log(getUserName());
console.log(getUserName("Олена"));Запис string | undefined означає, що значення може бути або рядком, або undefined.
noImplicitThisЗабороняє неявний тип any для this.
Це особливо важливо у функціях і методах, де контекст this може бути неочевидним. Тип this можна вказати спеціальним першим параметром функції:
interface Counter {
value: number;
}
function increase(this: Counter, amount: number): void {
this.value += amount;
}
const counter: Counter = {
value: 0
};
increase.call(counter, 5);
console.log(counter.value);Тепер TypeScript знає, що всередині increase значення this має властивість value типу number.
strictFunctionTypesПеревіряє сумісність типів функцій.
Це не дозволяє передати функцію, яка очікує більш спеціалізований тип, туди, де може бути передане ширше значення.
type Handler = (value: string | number) => void;
const printString = (value: string): void => {
console.log(value);
};
// Помилка: printString не може обробити число
// const handler: Handler = printString;Функція printString працює лише з рядками, а тип Handler допускає і рядки, і числа. Тому така заміна небезпечна.
Коректний варіант:
type Handler = (value: string | number) => void;
const printValue: Handler = (value) => {
console.log(value);
};
printValue("TypeScript");
printValue(42);strictBindCallApplyПеревіряє типи аргументів у методів bind, call та apply.
function add(a: number, b: number): number {
return a + b;
}
const result = add.call(null, 2, 3);
console.log(result);TypeScript перевіряє, що після null передано два числа.
Такий виклик буде помилковим:
function add(a: number, b: number): number {
return a + b;
}
// Помилка: аргументи мають бути числами
// add.call(null, "2", "3");Це корисно, тому що помилка в аргументах call, apply або bind виявляється ще до запуску програми.
strictPropertyInitializationПеревіряє, чи ініціалізовані властивості класу в конструкторі.
class User {
name: string;
constructor() {
// Помилка: властивість name не ініціалізована
}
}Властивість name оголошена як обов’язковий рядок, але їй не присвоєно значення.
Коректний варіант:
class User {
name: string;
constructor(name: string) {
this.name = name;
}
}
const user = new User("Олена");
console.log(user.name);Якщо властивість справді може бути відсутньою, це потрібно відобразити в типі:
class User {
name?: string;
}
const user = new User();
console.log(user.name);Тепер тип властивості — string | undefined, тому під час її використання потрібно враховувати відсутність значення.
useUnknownInCatchVariablesУ суворому режимі значення змінної в catch має тип unknown.
Будь-яке значення може бути передане в throw, тому TypeScript не може припустити, що помилка є об’єктом типу Error.
try {
throw new Error("Не вдалося виконати операцію");
} catch (error) {
if (error instanceof Error) {
console.log(error.message);
} else {
console.log("Невідома помилка");
}
}Перевірка error instanceof Error гарантує, що властивість message доступна.
Без такої перевірки TypeScript не дозволить безпечно звернутися до error.message:
try {
throw "Помилка";
} catch (error) {
// Помилка: error має тип unknown
// console.log(error.message);
}alwaysStrictДодає директиву "use strict" до скомпільованого JavaScript і аналізує файли в суворому режимі JavaScript.
Цей параметр входить до групи налаштувань, які вмикаються через strict: true.
Розглянемо функцію, яка шукає товар за ідентифікатором:
interface Product {
id: number;
name: string;
price: number;
}
const products: Product[] = [
{
id: 1,
name: "Клавіатура",
price: 1200
},
{
id: 2,
name: "Миша",
price: 800
}
];
function findProduct(id: number): Product | undefined {
return products.find((product) => product.id === id);
}
function formatProduct(id: number): string {
const product = findProduct(id);
if (product === undefined) {
return "Товар не знайдено";
}
return `${product.name}: ${product.price} грн`;
}
console.log(formatProduct(1));
console.log(formatProduct(99));Функція findProduct може не знайти товар, тому її тип повернення — Product | undefined.
Функція formatProduct перевіряє результат перед використанням. Завдяки цьому код безпечно працює і для наявного, і для відсутнього товару.
strictСувора перевірка допомагає знайти:
параметри функцій із неявним типом any;
можливе використання null або undefined;
неправильні типи аргументів;
невірне використання this;
неініціалізовані властивості класів;
небезпечну роботу зі значеннями з catch;
несумісні типи функцій.
Це зменшує кількість ситуацій, коли програма компілюється, але падає під час виконання.
У новому проєкті зазвичай достатньо одразу встановити:
{
"compilerOptions": {
"strict": true
}
}Якщо суворий режим додається до вже наявного проєкту, після його ввімкнення можуть з’явитися численні помилки. Їх потрібно виправляти поступово:
додати типи параметрам функцій;
перевірити місця, де значення може бути undefined;
ініціалізувати властивості класів;
перевірити обробку помилок;
повторно запустити компілятор.
Не варто вимикати всю сувору перевірку через одну помилку. Краще виправити конкретну причину.
any замість виправлення типуfunction process(value: any) {
return value.name;
}any приховує помилки. Краще описати очікувану структуру:
interface NamedValue {
name: string;
}
function process(value: NamedValue): string {
return value.name;
}undefinedconst names = ["Олена", "Іван"];
const name = names[10];
// Небезпечно: name може бути undefined
// console.log(name.toUpperCase());Потрібно перевірити значення:
const names = ["Олена", "Іван"];
const name = names[10];
if (name !== undefined) {
console.log(name.toUpperCase());
}!Оператор ! повідомляє TypeScript, що значення точно не є null або undefined:
const names = ["Олена", "Іван"];
const name = names[10];
console.log(name!.toUpperCase());У цьому прикладі оператор не робить значення безпечним. Якщо name справді дорівнює undefined, програма завершиться з помилкою під час виконання.
Краще виконати явну перевірку.
Не слід замінювати:
{
"compilerOptions": {
"strict": true
}
}на:
{
"compilerOptions": {
"strict": false
}
}лише через кілька помилок. Суворі перевірки є захистом проєкту, а помилки компілятора показують місця, які потребують уточнення типів.
strict: true вмикає набір суворих перевірок TypeScript.
noImplicitAny змушує явно вказувати типи там, де їх неможливо визначити.
strictNullChecks допомагає безпечно працювати з null і undefined.
strictPropertyInitialization перевіряє ініціалізацію властивостей класів.
useUnknownInCatchVariables змушує перевіряти значення помилок перед використанням.
strictFunctionTypes і strictBindCallApply перевіряють сумісність функцій та їхніх аргументів.
Суворий режим знаходить багато помилок на етапі компіляції та зменшує ризик помилок під час виконання.
У нових TypeScript-проєктах зазвичай варто одразу використовувати strict: true.