Головна / Статті

Основи TypeScript: Практичний посібник для розробників JavaScript

TypeScript для розробників JavaScript: практичний підхід — основні типи, tsconfig, режим суворості та поетапний шлях міграції, який робить код більш безпечним для змін у майбутньому.

Видавець: REACTAPP.TOP18 хв читання4117 слів

Джерела: TypeScript for JavaScript Developers: A Practical Beginner’s Guide

Якщо ви вже знаєте JavaScript, опанування TypeScript здається не стільки вивченням абсолютно нової мови, скільки розширенням тієї, яку ви вже розумієте.

Типовий JavaScript — це, по суті, JavaScript з доданим типовим системою, яка розташована над ним.

Ви продовжуєте працювати зі змінними, функціями, масивами, об’єктами, класами, обіцянками, async/await, модулями та практично з усім іншим, що вам вже знайоме. TypeScript пропонує набір інструментів, які допомагають виявляти помилки на ранніх етапах, ще до того, як ваш код буде виконаний у браузері чи на сервері.

Цей посібник розглядає концепції TypeScript, які є найбільш актуальними для розробників, які вже пишуть JavaScript.

Що таке TypeScript?

TypeScript — це мова, яка розташована над JavaScript.

У більшості випадків будь-яка програма на JavaScript, яку ви пишете, є також дійсним кодом на TypeScript. TypeScript додає можливість статичної перевірки типів, і в кінцевому підсумку компілюється у звичайний JavaScript, який працює в браузерах та на Node.js.

Візьмемо як приклад цей простий фрагмент коду на JavaScript:

function add(a, b) {
  return a + b;
}

Якщо переписати цю ж функцію на TypeScript, можна вказати, які типи значень вона приймає:

function add(a: number, b: number): number {
  return a + b;
}

Розберемо це детальніше:

  • a: number вимагає, щоб a був числом.
  • b: number вимагає, щоб b був числом.
  • Додане в кінець : number означає, що значення, яке повертає функція, є числом.

Завдяки цим анотаціям TypeScript може виявити неправильний виклик функції ще до початку її виконання:

add(10, 20);      // Correct
add("10", "20");  // TypeScript error

У звичайному JavaScript виклик функції з рядковими аргументами мовчки повертатиме "1020", оскільки оператор „+“ об’єднуватиме рядки замість того, щоб додавати числа. TypeScript виявляє таку ненавмисну поведінку заздалегідь.

Чому використовувати TypeScript?

Гнучкість JavaScript є його сильною стороною, але вона також може призвести до прихованих помилок.

Візьмемо цю функцію як приклад:

function calculateDiscount(price, percentage) {
  return price - price * percentage / 100;
}

Правильний виклик працює так, як і очікувалося:

calculateDiscount(1000, 10);

Але ніщо не заважає викликати її таким чином:

calculateDiscount("1000", "ten");

Проблема проявляється лише тоді, коли код насправді виконується.

За допомогою TypeScript можна вказати типи, які очікує функція:

function calculateDiscount(
  price: number,
  percentage: number
): number {
  return price - price * percentage / 100;
}

Тепер TypeScript миттєво позначає недійсні аргументи, не потрібно спочатку запускати код.

Деякі з основних переваг, які це принесе, включають:

  • Виявлення помилок під час написання коду
  • Покращена підтримка автодоповнення у вашому редакторі
  • Простіший та безпечніший рефакторинг
  • Більш чітка структура функцій та об’єктів
  • Краща співпраця над великими кодовими базами
  • Типи, які є вбудованою документацією

Цінність TypeScript стає особливо очевидною, коли проект переростає кілька файлів або бере участь більше одного розробника.

Встановлення TypeScript

TypeScript можна встановити глобально за допомогою:

npm install -g typescript

Щоб підтвердити версію встановлення, запустіть:

tsc --version

Потім створіть файл під назвою:

app.ts

Додайте до нього трохи коду TypeScript:

const message: string = "Hello TypeScript";
console.log(message);

Скомпілюйте файл за допомогою:

tsc app.ts

Це дасть скомпільований вихід у форматі JavaScript:

app.js

Ви можете безпосередньо запустити отриманий результат за допомогою Node.js:

node app.js

У продакшн-середовищах інструменти та фреймворки на кшталт React, Next.js, Angular та NestJS зазвичай автоматично виконують цей крок компіляції замість вас.

Файл tsconfig.json

Більшість проектів на TypeScript використовують файл tsconfig.json для налаштування компілятора.

Ви можете створити його за допомогою:

tsc --init

Мінімальна конфігурація може виглядати так:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "strict": true,
    "outDir": "./dist",
    "rootDir": "./src"
  }
}

Ось кілька найважливіших параметрів налаштувань:

target

Цей параметр визначає, яку версію JavaScript буде генерувати компілятор.

"target": "ES2020"

module

Цей параметр встановлює формат модуля, який використовується у результаті компіляції.

"module": "ESNext"

strict

Увімкнення цього режиму активує більш суворий рівень перевірки типів.

"strict": true

Для будь-якого нового проекту настійно рекомендується залишати суворий режим увімкненим.

rootDir

Це вказує компілятору, де знаходяться ваші вихідні файли TypeScript.

"rootDir": "./src"

outDir

Це визначає місце, куди слід записувати скомпільований JavaScript.

"outDir": "./dist"

Основні типи

TypeScript постачається з кількома примітивними типами, які ви вже знаєте.

Рядок

let username: string = "Vijeet";

Число

let experience: number = 10;

TypeScript не розрізняє цілі та десяткові числа; обидва належать до типу number.

let age: number = 35;
let price: number = 999.99;

Булевий тип

let isActive: boolean = true;

Null та Undefined

let emptyValue: null = null;
let missingValue: undefined = undefined;

У режимі суворості вам доведеться більш уважно керувати значеннями null та undefined.

Виведення типу

Вам не обов’язково вручну позначати кожне значення.

TypeScript часто може визначити тип змінної на основі того, що їй присвоєно.

let city = "Ahmedabad";

Тут TypeScript автоматично розпізнає city як рядок.

Спроба перепризначити його таким чином спричинить помилку:

city = 100;

Тут застосовується та сама логіка:

let total = 500;

TypeScript виводить, що total містить число.

Використання автоматичного виведення типу допомагає зробити код менш заплутаним. Залишайте явні анотації типу там, де вони справді покращують зрозумілість, наприклад у параметрах функцій, форматах відповідей API та складніших структурах об’єктів.

Масиви

Ось звичайний масив JavaScript:

const skills = ["JavaScript", "React", "Node.js"];

TypeScript дозволяє анотувати тип елементів масиву:

const skills: string[] = [
  "JavaScript",
  "React",
  "Node.js"
];

Його також можна написати за допомогою генеричної синтаксису:

const skills: Array<string> = [
  "JavaScript",
  "React",
  "Node.js"
];

Та сама ідея застосовується до числових масивів:

const scores: number[] = [75, 82, 91];

TypeScript блокує будь-які спроби вставити значення неправильного типу:

scores.push(95);       // Correct
scores.push("ninety"); // Error

Об’єкти

Ви можете надати звичайному JavaScript-об’єкту чітко визначену структуру.

const user: {
  name: string;
  age: number;
  isAdmin: boolean;
} = {
  name: "Vijeet",
  age: 35,
  isAdmin: true
};

Якщо властивість відсутня або має неправильний тип, TypeScript позначає це як помилку.

const user: {
  name: string;
  age: number;
} = {
  name: "Vijeet"
};

Тут у об’єкті відсутня необхідна властивість age.

Коли потрібно повторно використовувати однакову структуру об’єкта в кількох місцях, інтерфейси чи псевдоніми типів є кращим рішенням, ніж щоразу писати структуру вручну.

Інтерфейси

Інтерфейс визначає структуру, яку має мати об’єкт.

interface User {
  id: number;
  name: string;
  email: string;
  isActive: boolean;
}

Як тільки інтерфейс визначений, його можна повторно використовувати будь-де:

const user: User = {
  id: 1,
  name: "Vijeet",
  email: "vijeet@example.com",
  isActive: true
};

Інтерфейси стають корисними у таких ситуаціях:

  • опису деталей користувача, які зберігаються
  • моделювання елемента каталогу
  • перевірки полів, введених у форму
  • формування даних, які повертаються від API
  • визначення типу параметрів, які передаються до компонента
  • представлення рядка з таблиці бази даних

Наприклад:

interface Product {
  id: number;
  title: string;
  price: number;
}

Функція може приймати об’єкт Product як параметр:

function displayProduct(product: Product): void {
  console.log(`${product.title}: ₹${product.price}`);
}

Необов’язкові властивості

Деякі властивості об’єкта не завжди будуть присутніми.

Щоб позначити їх, додайте запитання після назви властивості:

interface User {
  id: number;
  name: string;
  phone?: string;
}

Обидва наступні об’єкти відповідають цьому інтерфейсу:

const userOne: User = {
  id: 1,
  name: "Amit"
};
const userTwo: User = {
  id: 2,
  name: "Neha",
  phone: "9876543210"
};

Оскільки phone є необов’язковим, його тип стає:

string | undefined

Це означає, що ви повинні перевірити його наявність перед використанням:

if (userTwo.phone) {
  console.log(userTwo.phone);
}

Псевдоніми типів

Псевдонім типу дозволяє призначити повторно використовувану назву будь-якому типу.

type UserId = number;

Потім ви можете використовувати цей псевдонім як тип:

const id: UserId = 101;

Псевдоніми типів особливо корисні при описі об’єднань чи складніших комбінацій типів.

type Status = "pending" | "approved" | "rejected";

З використанням цього псевдоніма дозволені лише три конкретні рядки:

let applicationStatus: Status = "pending";

Спроба використати щось інше призводить до помилки:

applicationStatus = "completed";

Інтерфейси проти псевдонімів типів

І інтерфейси, і псевдоніми типів можуть моделювати структуру об’єкта.

Ось версія з інтерфейсом:

interface Customer {
  name: string;
  email: string;
}

А ось еквівалентна версія з псевдонімом типу:

type Customer = {
  name: string;
  email: string;
};

Як приблизне правило для початківців:

  • Використовуйте interface, коли описуєте об’єкти чи структури класів.
  • Використовуйте type, коли працюєте з союзами типів, псевдонімами для примітивних типів, туплами чи більш складними комбінованими типами.

Однак це не є жорстким правилом – у багатьох випадках обидва підходи працюють однаково добре.

Союзні типи

Союзний тип дозволяє значенню мати один із кількох можливих типів.

let userId: string | number;

Обидва ці призначення є допустимими:

userId = 101;
userId = "USR-101";

Союзні типи стають корисними, коли дані з реального світу не завжди відповідають одному фіксованому формату.

function printId(id: string | number): void {
  console.log(id);
}

Перш ніж викликати метод, який існує лише у одному з можливих типів, спочатку потрібно обмежити діапазон значень:

function printId(id: string | number): void {
  if (typeof id === "string") {
    console.log(id.toUpperCase());
  } else {
    console.log(id.toFixed(0));
  }
}

Цю техніку називають звуженням типу.

Літеральні типи

Літеральні типи обмежують змінну точним, заздалегідь визначеним набором значень.

type Theme = "light" | "dark" | "system";

Це присвоєння є прийнятним:

let selectedTheme: Theme = "dark";

Але це присвоєння відхиляється:

selectedTheme = "blue";

Літеральні типи добре підходять у таких випадках:

  • текущий статус запису
  • рівень дозволів, призначений користувачеві
  • налаштування візуальної теми
  • візуальний стиль кнопки
  • HTTP-дія, яка використовується у запиті
  • режим, у якому працює додаток

Як приклад:

type UserRole = "admin" | "editor" | "customer";

Функції

Для параметрів функції тип вказується одразу після назви параметра.

function greet(name: string): string {
  return `Hello, ${name}`;
}

Тип значення, яке повертає функція, вказується після закриваючої дужки списку параметрів.

function multiply(a: number, b: number): number {
  return a * b;
}

Якщо функція не повертає значення, позначте її як void.

function logMessage(message: string): void {
  console.log(message);
}

Необов’язкові параметри позначаються символом ?:

function greetUser(
  name: string,
  title?: string
): string {
  if (title) {
    return `Hello, ${title} ${name}`;
  }
 return `Hello, ${name}`;
}

Значення параметрів за замовчуванням поводяться так само, як і в звичайному JavaScript:

function calculateTax(
  amount: number,
  rate: number = 18
): number {
  return amount * rate / 100;
}

Типування функцій-стрілок

Функції-стрілки можна анотувати таким самим способом.

const subtract = (
  a: number,
  b: number
): number => {
  return a - b;
};

Ось більш компактна форма:

const subtract = (
  a: number,
  b: number
): number => a - b;

Тип any

Якщо присвоїти значенню тип any, TypeScript припиняє його перевірку повністю.

let data: any = "Hello";
data = 100;
data = true;
data = { name: "Vijeet" };

Хоча спочатку це може здаватися зручним, надмірне використання any позбавляє нас більшості переваг TypeScript.

Ось приклад:

function processData(data: any): any {
  return data.someProperty.someMethod();
}

TypeScript не може нічого зробити, щоб виявити помилки в цій функції.

Залиште any для ситуацій, коли це справді неминуче — наприклад, під час поступової трансформації кодбази на JavaScript або при роботі з даними від сторонніх постачальників, які не мають належних визначень типів.

Тип unknown

unknown надає безпечний спосіб представлення значень, тип яких не відомий заздалегідь.

let value: unknown;

Як і any, він приймає будь-які значення:

value = "Hello";
value = 100;
value = true;

Але на відміну від any, TypeScript змушує вас узагальнити тип перед тим, як можна буде його використати:

if (typeof value === "string") {
  console.log(value.toUpperCase());
}

Це робить unknown підходящим для:

  • Даних, отриманих з зовнішніх API
  • Значень, розпарсованих з JSON
  • Об’єктів помилок, захоплених у блоку try/catch
  • Даних, наданих користувачами
  • Будь-чого, форма якого ще не визначена

Твердження типів

Іноді у вас є більше інформації про значення, ніж TypeScript може вивести самостійно.

Твердження типу дозволяє вам сказати компілятору, як обробляти це значення.

const input = document.getElementById(
  "email"
) as HTMLInputElement;

Після здійснення твердження ви можете отримати доступ до властивостей, специфічних для цього типу:

console.log(input.value);

Пам’ятайте, що твердження нічого не змінює під час виконання — воно лише змінює те, як TypeScript інтерпретує значення під час компіляції.

Через це слід використовувати твердження обережно та лише тоді, коли ви впевнені у фактичній структурі даних.

Тупли

Тупл — це масив із фіксованою кількістю елементів, де кожна позиція має свій визначений тип.

let userEntry: [number, string];
userEntry = [1, "Vijeet"];

Тут перша позиція має містити число, а друга — рядок.

Наступний варіант призведе до помилки:

userEntry = ["Vijeet", 1];

Туплі добре підходять для невеликих даних фіксованої форми або парних значень:

type Coordinate = [number, number];
const location: Coordinate = [23.0225, 72.5714];

Коли ваші дані стають складнішими або потребують описових імен полів, звичайні об’єкти, як правило, є зрозумілішими.

Enums

Enum дозволяє визначити фіксовану групу іменованих констант.

enum OrderStatus {
  Pending,
  Processing,
  Shipped,
  Delivered
}

Ви можете посилатися на них ось так:

let status: OrderStatus = OrderStatus.Processing;

Надання enum рядкових значень часто покращує читабельність:

enum PaymentStatus {
  Pending = "pending",
  Paid = "paid",
  Failed = "failed"
}

Проте багато користувачів TypeScript віддають перевагу типам-уніонам, особливо для простіших сценаріїв:

type PaymentStatus =
  | "pending"
  | "paid"
  | "failed";

Типи-уніони зазвичай компілюються у менший об’єм JavaScript та є хорошим стандартним варіантом для більшості коду фронт-енду.

Класи

TypeScript розширює звичайні класи JavaScript за допомогою перевірки типів.

class Employee {
  name: string;
  salary: number;
  constructor(name: string, salary: number) {
    this.name = name;
    this.salary = salary;
  }  getAnnualSalary(): number {
    return this.salary * 12;
  }
}

Створення екземпляра класу виглядає так само, як у JavaScript:

const employee = new Employee("Rahul", 50000);
console.log(employee.getAnnualSalary());

Модифікатори доступу також є частиною синтаксису класів у TypeScript.

class BankAccount {
  public accountHolder: string;
  private balance: number;
  constructor(accountHolder: string, balance: number) {
    this.accountHolder = accountHolder;
    this.balance = balance;
  }  public getBalance(): number {
    return this.balance;
  }
}

Основні модифікатори є наступними:

  • public: видимий з будь-якого місця
  • private: видимий лише всередині самого класу
  • protected: видимий усередині класу та всіх його підкласів
  • readonly: може бути встановлений один раз, але не може бути перезначений пізніше

Генерики

Генерики дозволяють писати гнучкий, повторно використовуваний код, який все одно зберігає повну безпеку типів для різних типів даних.

Візьміть цю функцію як вихідну точку:

function returnValue(value: any): any {
  return value;
}

Оскільки вона базується на any, TypeScript не може сказати вам нічого про те, що з неї буде отримано.

Переписування коду з використанням універсального параметра вирішує цю проблему:

function returnValue<T>(value: T): T {
  return value;
}

Тепер тип значення, яке повертається, збігається з тим, що було передано:

const text = returnValue<string>("Hello");
const count = returnValue<number>(100);

У багатьох випадках TypeScript може автоматично визначити універсальний тип, тож не потрібно його вказувати вручну:

const text = returnValue("Hello");
const count = returnValue(100);

Універсальні типи постійно використовуються під час роботи з масивами, структурами відповідей API, повторно використовуваними компонентами інтерфейсу, користувацькими хуками та допоміжними функціями.

function getFirstItem<T>(items: T[]): T | undefined {
  return items[0];
}

Використовується ось так:

const firstNumber = getFirstItem([10, 20, 30]);
const firstName = getFirstItem(["Amit", "Neha"]);

Обіцянки та асинхронні функції

Функції, оголошені з ключовим словом async, завжди повертають обіцянки.

async function getUsername(): Promise<string> {
  return "Vijeet";
}

Асинхронна функція, яка повертає об’єкт користувача, може виглядати ось так:

interface User {
  id: number;
  name: string;
}
async function getUser(): Promise<User> {
  return {
    id: 1,
    name: "Vijeet"
  };
}

А для списку користувачів тип значення, яке повертається, потрібно обгорнути в масив:

async function getUsers(): Promise<User[]> {
  return [
    { id: 1, name: "Vijeet" },
    { id: 2, name: "Rahul" }
  ];
}

Надання результатам API належних типів у такий спосіб захищає решту вашого кодового базису від помилок у подальшій роботі.

Визначення типів відповідей API

interface Product {
  id: number;
  title: string;
  price: number;
}

Ви можете обгорнути виклик fetch у функцію, яка визначає тип її повернення:

async function fetchProducts(): Promise<Product[]> {
  const response = await fetch("/api/products");
  if (!response.ok) {
    throw new Error("Unable to fetch products");
  }  const data: Product[] = await response.json();  return data;
}

Є один момент, який варто пам’ятати: TypeScript не має можливості перевіряти ці дані після того, як додаток почав працювати.

Ця рядок:

const data: Product[] = await response.json();

лише вказує компілятору обробляти розпарсену відповідь як Product[] — він не підтверджує, що сервер дійсно надіслав об’єкти саме такої форми.

У додатках, де важлива точність, розробники часто поєднують TypeScript із бібліотекою перевірки на час виконання, такою як Zod, щоб усунути цю прогалину.

Робота з елементами DOM

Типи елементів браузера вже є у TypeScript.

const button = document.querySelector(
  "#submit-button"
);

Компілятор знає, що цей запит може повернутися порожнім, тому тип результату включає null разом із типом елемента.

Це означає, що перед використанням потрібно перевірити наявність елемента:

if (button) {
  button.addEventListener("click", () => {
    console.log("Button clicked");
  });
}

Якщо вам потрібен більш конкретний тип елемента, ви можете це перевірити:

const emailInput = document.querySelector(
  "#email"
) as HTMLInputElement | null;

Потім отримайте його значення після підтвердження наявності:

if (emailInput) {
  console.log(emailInput.value);
}

TypeScript не замінює перевірку під час виконання

Цей момент варто підкреслити, особливо для розробників, які переходять з JavaScript.

Перевірки в TypeScript відбуваються лише під час розробки та компіляції. Як тільки ваш код буде скомпільований у JavaScript, усі анотації типів зникають.

Візьмемо цю функцію:

function double(value: number): number {
  return value * 2;
}

Після компіляції вона стає приблизно такою:

function double(value) {
  return value * 2;
}

На той момент не залишається жодних слідів початкової інформації про типи, які можна було б використати для перевірки чогось.

У результаті TypeScript не може гарантувати наступне:

  • API дійсно повернуло правильно сформовані дані
  • Користувач ввів коректне значення
  • Запис у базі даних відповідає очікуваній структурі
  • Сервіс третьої сторони дотримався свого задокументованого контракту

Будь-які дані, що надходять ззовні вашого коду, все одно потрібно перевіряти під час роботи програми.

Міграція існуючого проекту JavaScript

Перетворення кодової бази JavaScript на TypeScript не обов’язково має відбуватися одним масштабним переписуванням.

Поетапна міграція, як правило, краще працює на практиці.

Крок 1: Встановити TypeScript

npm install --save-dev typescript

Крок 2: Створити tsconfig.json

npx tsc --init

Крок 3: Тимчасово дозволити JavaScript

{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": false
  }
}

Крок 4: Поступово змінюйте назви файлів

Змініть файл приблизно так:

utils.js

на:

utils.ts

А для компонентів React перетворіть:

Button.jsx

на:

Button.tsx

Крок 5: Виправляйте помилки по одному файлу

Корисно почати з функцій-інструментів, спільних моделей даних та менших компонентів, залишивши більш складну логіку програми на пізніший час.

Цей поступовий підхід є однією з найбільших практичних переваг TypeScript при його впровадженні у існуючий проект.

Поширені помилки, яких роблять розробники JavaScript

Використання any скрізь

const user: any = getUser();

Це може приховати негайну скаргу компілятора, але водночас усуне всю перевірку типів.

Кращим підходом є визначення справжнього інтерфейсу:

interface User {
  id: number;
  name: string;
}

Додавання типів до кожної змінної

Немає потреби писати це:

const name: string = "Vijeet";
const count: number = 10;
const active: boolean = true;

адже механізм виведення типу вже самостійно визначає ці типи:

const name = "Vijeet";
const count = 10;
const active = true;

Залишайте явні анотації для тих місць, де вони справді покращують зрозумілість.

Ігнорування null

Цей код може зламатися під час виконання:

const element = document.querySelector("#app");
element.innerHTML = "Hello";

Елемент, який шукається, може просто не існувати на сторінці.

Краще захиститися від такої можливості:

const element = document.querySelector("#app");
if (element) {
  element.innerHTML = "Hello";
}

Використання тверджень про типи для приховування проблем

Писати щось подібне — це ризиковано:

const user = apiResponse as User;

Твердження не перевіряє нічого щодо фактичної відповіді API — воно просто просить компілятор повірити вашим словам.

Розгляд TypeScript як окремого середовища виконання

TypeScript не виконується браузером безпосередньо. Його спочатку компілюють у звичайний JavaScript, перш ніж він почне працювати.

Це означає, що все, що ви вже знаєте про JavaScript, залишається актуальним.

Практичний приклад

Розгляньмо простий кошик покупок, написаний у тому форматі, як ви зазвичай створюєте його на JavaScript, але тепер із додаванням типів TypeScript.

interface CartItem {
  id: number;
  name: string;
  price: number;
  quantity: number;
}

function calculateCartTotal(
  items: CartItem[]
): number {
  return items.reduce((total, item) => {
    return total + item.price * item.quantity;
  }, 0);
}
const cart: CartItem[] = [
  {
    id: 1,
    name: "Keyboard",
    price: 2500,
    quantity: 1
  },
  {
    id: 2,
    name: "Mouse",
    price: 1200,
    quantity: 2
  }
];
const total = calculateCartTotal(cart);
console.log(`Cart total: ₹${total}`);

Завдяки цьому функція тепер захищена від некоректних даних у кошику.

Наприклад, наступний фрагмент коду не вдасться скомпілювати:

const invalidCart: CartItem[] = [
  {
    id: 1,
    name: "Keyboard",
    price: "2500",
    quantity: 1
  }
];

Проблема полягає у тому, що price встановлений як рядок, хоча мав би бути числом.

Чи повинен кожен проект на JavaScript використовувати TypeScript?

Не завжди.

Звичайний JavaScript все ще добре підходить для таких випадків:

  • Невеликі експерименти
  • Прості скрипти
  • Швидкі прототипи
  • Базові сторінки-лендінги
  • Тимчасові внутрішні інструменти
  • TypeScript зазвичай приносить більшу користь у таких ситуаціях:

    • Великі фронтенд-застосунки
    • Кодові бази React та Next.js
    • Бекенд-сервіси Node.js
    • Кодові бази, якими користуються кілька команд
    • Продукти з довгим терміном існування
    • Проекти, що працюють із складними структурами даних
    • Застосунки, створені та підтримувані кількома розробниками

    Загалом, чим більшим та довготривалим є проект, тим більшу користь ви отримуєте від використання TypeScript.

    Заключні міркування

    TypeScript — це не заміна JavaScript; він покращує процес написання коду на JavaScript, додаючи додатковий рівень безпеки.

    Як людина, яка починала з JavaScript, ви вже маєте більшу частину необхідних знань:

    • Змінні
    • Функції
    • Об’єкти
    • Масиви
    • Класи
    • Обіцянки
    • Модулі
    • Асинхронний код

    Те, що залишилося вивчити, — це переважно способи представлення структури ваших даних.

    Хорошим початком є:

    1. Примітивні типи
    2. Типи параметрів та значень для функцій
    3. Інтерфейси
    4. Типи об’єднання
    5. Необов’язкові властивості
    6. Генерики
    7. Типовані відповіді від API

    Не намагайтеся одразу опанувати всі складні функції. Почніть з анотацій у звичайному JavaScript та дозвольте потребам ваших проектів визначати, що вивчати далі.

    Коли TypeScript стане частиною вашої роботи, повернення до звичайного, нетипованого JavaScript може здатися несподівано небезпечним.