|).Протягом усього курсу ми писали код “чистим” (ванільним) JavaScript. Одна з його найголовніших особливостей полягає в тому, що він є мовою з динамічною типізацією. Це означає, що коли ви створюєте змінну let x = 10, JavaScript мовчки дозволить вам через дві строчки написати x = "Привіт", а потім x = []. JavaScript байдуже, що лежить у змінній.
Для маленьких скриптів це дуже зручно і швидко. Але коли ваш проект виростає до тисяч файлів і десятків розробників у команді, ця лояльність обертається справжнім жахом.
Уявіть, що Марія (Backend Developer) написала функцію для розрахунку знижки calculateDiscount(price). А Іван (Frontend Developer) випадково передав у неї рядок calculateDiscount("100 доларів"). JavaScript не скаже Івану про помилку під час написання коду. Додаток здаватиметься робочим, Іван відправить його на сервер, і вже там, ОНЛАЙН, перед справжнім клієнтом, браузер спробує поділити рядок на число і видасть NaN (або TypeError: undefined is not a function). Додаток епічно “впаде” (Runtime Exception).
Як цьому запобігти? Нам потрібен суворий контрольор, який перевірить типи всіх змінних ЩЕ ДО того, як ви запустите код. Знайомтесь — TypeScript.
Мета цієї лекції — зрозуміти філософію суворої типізації та розібрати синтаксис інструменту, який на сьогодні став обов’язковим “законним” стандартом для всієї світової Frontend та Backend розробки.
TypeScript (TS) — це мова програмування (а точніше — лінтер/аналізатор на стероїдах), розроблена компанією Microsoft (автором мови C#).
Головне правило TypeScript: Будь-який правильний JavaScript-код є правильним TypeScript-кодом. Звучить дивно? Справа в тому, що TS — це просто Надмножина (Superset). Він бере звичайний JS і просто “наклеює” поверх нього свої нові можливості (анотації типів).
Як це працює фізично:
.ts (або .tsx для React) замість .js.tsc або Vite). Вона сканує ваш код на наявність логічних помилок (де ви намагаєтесь поділити рядок на масив).bundle.js, який відправляється у браузер.Браузер НІКОЛИ не бачить і не знає про існування TypeScript. Він виконує тільки чистий згенерований JavaScript.
Щоб повідомити компілятору, який саме тип даних ви очікуєте, ставиться двокрапка : одразу після назви змінної.
// 1. Примітиви (String, Number, Boolean)
let userName: string = "Петро";
let userAge: number = 25;
let isActive: boolean = true;
// Якщо ви спробуєте порушити правило, VS Code одразу підкреслить код червоним:
// userName = 500;
// ^^^ Помилка: Тип 'number' неможливо призначити типу 'string'
// 2. Масиви
// Треба вказати, з ЧОГО складається масив. Додаємо [] після типу:
let prices: number[] = [100, 200, 300];
let names: string[] = ["Київ", "Львів", "Одеса"];
// prices.push("Безкоштовно");
// ^^^ Помилка
Примітка: У 90% випадків TS настільки розумний (Type Inference - Виведення типів), що якщо ви одразу ініціалізуєте змінну, йому не треба нічого писати. Код let city = "Київ"; автоматично буде вважатися string назавжди.
Найголовніша сила TS розкривається під час роботи з об’єктами. Коли ви отримуєте об’єкт користувача з сервера, звідки вам знати, як правильно написати в коді: user.firstName чи user.first_name? Доводиться відкривати Postman і гуглити структуру бази.
З TS ми ПРОЕКТУЄМО форму об’єктів заздалегідь, створюючи “Контракти” за допомогою інструменту Interface або Type. Вони майже ідентичні.
// Створюємо креслення (Інтерфейс) для Юзера
interface User {
id: number;
firstName: string;
lastName: string;
age: number;
isAdmin: boolean;
}
// Тепер ми створюємо реальний об'єкт і зобов'язуємо його відповідати кресленню User
const myCurrentBoss: User = {
id: 1,
firstName: "Ілон",
lastName: "Маск",
age: 53,
isAdmin: true,
};
// Контроль працює в обидві сторони!
// 1. Якщо ви забудете написати 'isAdmin', об'єкт засвітиться червоним ("Відсутня властивість isAdmin").
// 2. Якщо ви напишете console.log(myCurrentBoss.emaillll), код не скомпілюється ("Властивості 'emaillll' не існує в типі 'User'").
Ще одна неймовірна перевага: коли ви поставите крапку myCurrentBoss., редактор VS Code (який збудований на TS) миттєво відкриє вам список з усіма доступними полями (Intellisense), бо він знає структуру! Вам не треба нічого запам’ятовувати.
Іноді в об’єкті деякі поля не є обов’язковими. Наприклад, в Інтернет-магазині юзер може вказати свій номер телефону, а може й ні. Щоб TS не сварився на відсутність поля, ставимо знак питання ? перед двокрапкою.
interface Customer {
id: number;
name: string;
phone?: string; // Це поле не є обов'язковим (може бути string або undefined)
}
А що робити, якщо якась змінна може бути двох абсолютно різних типів? Наприклад, ID з бази може прийти як число 15, а може прийти як рядок у форматі UUID 'abc-45-de'. Ми використовуємо Union Types (Об’єднання типів) через вертикальну лінію |.
// Змінна може бути АБО числом, АБО рядком
let serverResponseId: number | string;
serverResponseId = 404; // OK
serverResponseId = "Success"; // OK
// serverResponseId = true; // ПОМИЛКА
Дуже часто Union типи використовують для жорсткого обмеження конкретних значень-рядків (Літеральні типи):
let userStatus: "online" | "offline" | "banned";
userStatus = "online"; // OK
// userStatus = "playing"; // ПОМИЛКА: Тип '"playing"' не належить до трьох дозволених.
Під час написання функцій ми повинні типізувати ДВІ речі:
return (значення повернення).// 1. Аргументи (message: string, count: number)
// 2. Значення повернення (: string)
function buildMessage(message: string, count: number): string {
return `${message}. Повторень: ${count}`;
}
const finalGreeting = buildMessage("Привіт", 5);
// Типізація стрілочної функції
const multiply = (x: number, y: number): number => {
return x * y;
};
Якщо ваша функція нічого не повертає назовні return (просто робить console.log або змінює глобальну змінну), її тип повернення називається void (порожнеча).
function logError(errorMsg: string): void {
console.error(`Увага: ${errorMsg}`);
}
Найбільший біль у великому React-додатку — це намагатися з’ясувати, які саме Пропси чекає компонент <ProductCard>, який написав ваш колега півроку тому.
З TypeScript ми створюємо interface спеціально для Пропсів цього компонента.
// файл ProductCard.tsx (зверніть увагу на розширення .tsx!)
import React from "react";
// 1. Описуємо "Очікування" (Контракт)
interface ProductCardProps {
title: string;
price: number;
imageUrl?: string; // Картинка необов'язкова
isDiscounted: boolean;
}
// 2. Застосовуємо ці очікування до аргументу props (через деструктуризацію)
export function ProductCard({
title,
price,
imageUrl,
isDiscounted,
}: ProductCardProps) {
return (
<div className="card">
{imageUrl ? (
<img src={imageUrl} alt={title} />
) : (
<div className="placeholder" />
)}
<h3>{title}</h3>
<p>
Ціна: {price} грн {isDiscounted && <span>(Зі знижкою!)</span>}
</p>
</div>
);
}
Що тепер станеться в App.tsx?
Як тільки ви напишете <ProductCard>, VS Code миттєво підкреслить вам його червоним з повідомленням: “Гей, ти забув передати обов’язковий пропс title!”.
Коли ви почнете вводити title="...", редактор автоматично підкаже, які ще пропси можна передати і їхній тип (price вимагатиме число, а не рядок).
interface) або Типи. Вони створюють суворі інженерні креслення об’єктів (наприклад, описують сутність “Користувач”).? біля ключа phone?: string; створює Опціональне поле, яке можна передати, а можна і пропустити. Об’єднання | у правилі “Union Types” каже системі, що змінна може належати до різних родин типів (наприклад string | number).(name: string) та обов’язкового опису вихідного значення після дужок (): void.<Button size={10} /> редактор миттєво підкреслить атрибут червоним (якщо за інструкцією розмір там має бути рядком "large").bundle.js, який віддає сервер на хостингу?? відразу після імені ключа об’єкта (в межах “Interface”)? Яке значення JS може ховатися на цьому місці окрім бажаного стрінгу (рядка)?| під назвою “Union type”. Коли це може знадобитися у роботі з функцією приймання ідентифікаторів товарів з бази даних?void після закриваючої круглої дужки функції function sayHello(...) : void?UserCard приймає в себе пропси імені, та статусу (active чи не active), як за допомогою TypeScript захистити іншого розробника від того, щоб він випадково не передав цей status у форматі звичайного стрінгу “ОК”? Складіть цей “Контракт Пропсів” в голові.