Розроблення фронтенду сайту на TypeScript
TypeScript — це не просто «JavaScript з типами». Це інструмент, який робить рефакторинг передбачуваним, документує контракти між модулями та ловить цілий клас помилок на етапі компіляції. Для проектів з командою від двох осіб або сроком життя більше року TypeScript — не опція, а базова вимога.
Ми використовуємо TypeScript як основну мову для всього фронтенду: від конфігурації Vite до типізації API-відповідей.
Конфігурація для строгого TypeScript
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"exactOptionalPropertyTypes": true,
"paths": {
"@/*": ["./src/*"]
}
}
}
strict: true включає 8 флагів розом. noUncheckedIndexedAccess додає undefined до типу при доступі до масиву по індексу — половина runtime-помилок зникає сама по собі.
Типізація API
Типи для API-відповідей — один з перших кроків на будь-якому проекті. Ручне написання утомливо і застаріває разом з бекендом. Правильний підхід:
OpenAPI → автогенерація типів:
npx openapi-typescript https://api.example.com/openapi.json -o src/types/api.ts
Результат — точні типи для всіх endpoint'ів. Потім типобезпечний клієнт:
import createClient from 'openapi-fetch';
import type { paths } from '@/types/api';
const client = createClient<paths>({ baseUrl: 'https://api.example.com' });
// TypeScript знає типи параметрів та відповіді
const { data, error } = await client.GET('/products/{id}', {
params: { path: { id: '42' } }
});
if (data) {
console.log(data.name); // string — без as, без any
}
Паттерни для масштабованого фронтенду
Discriminated union для станів завантаження:
type AsyncState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; message: string };
function renderState<T>(state: AsyncState<T>): string {
switch (state.status) {
case 'idle': return 'Натисніть для завантаження';
case 'loading': return 'Завантаження...';
case 'success': return `Завантажено: ${JSON.stringify(state.data)}`;
case 'error': return `Помилка: ${state.message}`;
}
}
Компілятор перевіряє exhaustiveness — якщо додати новий статус, всі switch-вирази без нього стають помилкою.
Branded types для запобігання плутанини ID:
type UserId = string & { readonly __brand: 'UserId' };
type ProductId = string & { readonly __brand: 'ProductId' };
function toUserId(id: string): UserId { return id as UserId; }
function getUser(id: UserId): Promise<User> { ... }
const productId: ProductId = toProductId('abc');
getUser(productId); // Помилка компіляції: ProductId не сумісна з UserId
Zod для валідації runtime-даних:
import { z } from 'zod';
const ProductSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1).max(255),
price: z.number().positive(),
category: z.enum(['electronics', 'clothing', 'books']),
tags: z.array(z.string()).default([]),
});
type Product = z.infer<typeof ProductSchema>; // Тип виведено автоматично
// Валідація відповіді API
const raw = await fetch('/api/products/42').then(r => r.json());
const product = ProductSchema.parse(raw); // Throws якщо невалідно
Налаштування линтингу
// .eslintrc або eslint.config.js
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/strict-type-checked",
"plugin:@typescript-eslint/stylistic-type-checked"
],
"rules": {
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/no-floating-promises": "error"
}
}
no-floating-promises ловить незавершені promise-ланцюги — цілий клас помилок, які інакше мовчки проглатуються.
Інтеграція з фреймворками
TypeScript працює з будь-яким фронтенд-стеком:
| Фреймворк | Рівень підтримки |
|---|---|
| React 18 | Повна, JSX через tsx |
| Vue 3 | Повна, SFC через <script setup lang="ts"> |
| Svelte 4/5 | Через lang="ts" у script-блоці |
| Solid.js | Першокласна підтримка |
| Vanilla (без фреймворка) | Повна |
Терміни
- Тиждень 1: налаштування tsconfig, ESLint, генерація типів з OpenAPI/GraphQL схем
- Тижні 2–3: розроблення компонентів та бізнес-логіки з повною типізацією
-
Тиждень 4: code review на наявність
any, рефакторинг слабо типізованих місць, тести з Vitest
Проект здаватися з нульовими any в продакшн-коді та включеним strict: true. Исключення документуються явним комментарем.







