FAQ Портал
Категорії
Пошук
Про нас
Контакти
UK
RU
EN
Головна
Технології
Програмування
TypeScript
TypeScript
100 питань
Як встановити TypeScript у проект?
•
npm i -D typescript.
•
npx tsc --init створить tsconfig.json.
•
Додай скрипти: tsc, tsc -w.
•
Для Node: npm i -D ts-node.
•
Перевір: npx tsc -v.
Що таке tsconfig.json і за що він відповідає?
•
Це конфігурація компілятора.
•
target/module визначають вихідний JS.
•
strict включає строгі перевірки.
•
include/exclude керують файлами.
•
paths/baseUrl налаштовують алиаси.
Чим відрізняються type і interface?
•
interface розширюється через extends.
•
interface підтримує declaration merging.
•
type зручний для union/intersection.
•
Для об'єктів частіше беруть interface, але це не правило.
•
У реальності вибирай за задачею і стилем команди.
Що таке strict mode у TypeScript і чому його варто вмикати?
•
strict включає набір строгих флагів.
•
Ловить помилки з null/undefined і типами.
•
Покращує автодоповнення і рефакторинг.
•
Підвищує якість коду у великих проектах.
•
Вмикай поступово, якщо проект старий.
Що таке any і чому його варто уникати?
•
any вимикає перевірку типів.
•
Помилки переходять у runtime.
•
Замість any використовуйте unknown, generics або точні типи.
•
Для міграції можна тимчасово використовувати any, але з планом прибрати.
•
Можна обмежити через eslint/tsconfig.
Чим відрізняється unknown від any?
•
unknown безпечніше: його не можна використовувати без перевірки.
•
Вимагає narrowing (typeof, in, instanceof).
•
Підходить для зовнішніх даних (JSON).
•
any — 'дірка' у типах.
•
З unknown помилки ловляться на етапі компіляції.
Як типізувати результат JSON.parse?
•
JSON.parse повертає any.
•
Використовуй unknown і валідовуй структуру.
•
Створюй type guard або схему (zod).
•
Після валідacji — приведи до потрібного типу.
•
Не роби сліпий as YourType без перевірки.
Що таке type narrowing і як він працює?
•
Це звуження типу у гілках коду.
•
Використовуй typeof для примітивів.
•
Використовуй in/instanceof для об'єктів/класів.
•
Користувацькі type guards також звужують тип.
•
Допомагає писати код без зайвих кастів.
Як написати функцію type guard?
•
Функція повертає вираз виду x is T.
•
Внутрішньо перевіряй поля і типи.
•
Використовуй для unknown/union.
•
Тримай перевірки простими і покривай тестами.
•
Валідація схемою (zod) часто надійніша.
Що таке union types і де вони корисні?
•
Union: A | B.
•
Добре для обмежених наборів значень.
•
Часто використовують з дискримінуючим полем.
•
Вимагає narrowing перед доступом до специфічних полів.
•
Покращує виразність API.
Що таке intersection types і коли їх використовувати?
•
Intersection: A & B.
•
Об'єднує властивості кількох типів.
•
Зручно для композицій і міксинів.
•
Обережно з конфліктуючими полями.
•
Часто зустрічається у типах бібліотек.
Що таке literal types і навіщо вони потрібні?
•
Типи літералів: 'GET', 200, true.
•
Основи для union з конкретних значень.
•
Зручно для статусів, ролей, режимів.
•
Працюють разом з as const.
•
Допомагають уникнути помилок при друку.
Навіщо потрібен as const?
•
Робить літерали незмінними і вузькими.
•
Перетворює масив у readonly tuple.
•
Корисно для конфігів і словників.
•
Спрощує виведення типів.
•
Часто використовується з satisfies.
Що таке satisfies і чим він краще 'as'?
•
satisfies перевіряє відповідність типу, але зберігає вивід.
•
Не 'зажимає' значення як as.
•
Корисно для конфігів і мапінгів.
•
Допомагає ловити помилки ключів/полів.
•
Доступно в TS 4.9+.
Як типізувати об'єкт-словник з фіксованими ключами?
•
Використовуй Record<K, V>.
•
K може бути union літералів.
•
Для часткових ключів — Partial<Record<...>>.
•
Для перевірки без втрати виводу — satisfies.
•
Для динаміки — index signature.
Що таке index signature і коли він потрібен?
•
{[key: string]: Value}.
•
Для об'єктів з невідомими ключами.
•
Обмежує тип усіх значень.
•
Може конфліктувати з конкретними полями — обережно.
•
Іноді краще Map<string, V>.
Як типізувати масив з фіксованою структурою (tuple)?
•
Tuple: [number, string].
•
Можна робити readonly tuple через as const.
•
Для іменованих елементів: [id: string, value: number].
•
Зручно для пар key-value.
•
Для великих структур краще interface.
Що таке generics і навіщо вони потрібні?
•
Дозволяють параметризувати типи.
•
Наприклад: function first<T>(a: T[]): T.
•
Убирають дублювання коду.
•
Можна обмежувати T через extends.
•
Покращують типізацію бібліотек.
Як обмежувати generics через extends?
•
<T extends { id: string }>.
•
Тоді у T гарантовано є id.
•
Можна обмежувати union'ом.
•
Для ключів використовуйте extends keyof.
•
Обмеження покращують автодоповнення.
Як типізувати функцію getProperty(obj, key)?
•
<T, K extends keyof T>(obj: T, key: K) => T[K].
•
keyof дає набір ключів.
•
T[K] повертає тип значення за ключем.
•
Працює і з optional полями.
•
Це канонічний приклад generics.
Що таке keyof і чому він корисний?
•
keyof T дає union ключів типу.
•
Дозволяє безпечно індексувати.
•
Зручний у утилітах Pick/Omit.
•
Допомагає створювати типобезпечні API.
•
Працює разом з mapped types.
Що таке mapped types?
•
Це типи виду { [K in keyof T]: ... }.
•
Дозволяють трансформувати поля.
•
На них основані Partial/Required/Readonly.
•
Можна змінювати модифікатори: -? / +readonly.
•
Потужний інструмент для бібліотек.
Як працює Partial<T> і коли його використовувати?
•
Робить усі поля optional.
•
Зручно для патч-об'єктів (update).
•
Небезпека: втрачається гарантія наявності полів.
•
Часто краще Partial<Pick<T, ...>>.
•
Для форми введення — хороший варіант.
У чому різниця між Pick і Omit?
•
Pick бере підмножину полів.
•
Omit виключає поля.
•
Зручно для DTO і публічних моделей.
•
Уникайте дублювання структур.
•
Комбінуйте з Partial/Required.
Що таке Record<K, V> і де він корисний?
•
Record створює об'єкт з ключами K і значеннями V.
•
Зручно для словників і маппінгів.
•
K може бути union'ом.
•
Для неповних ключів використовуйте Partial<Record<...>>.
•
Для суворої перевірки ключів — satisfies.
Як типізувати функції зворотного виклику (callbacks)?
•
Опиши сигнатуру: type Fn = (x: number) => string.
•
Для подій — використовуй типи бібліотеки (React, DOM).
•
Для async — Promise<...>.
•
Не забувай про опційні параметри.
•
Зроби явним повернене значення.
Як типізувати Promise та async/await?
•
async функція повертає Promise<T>.
•
Вкажи тип результату: Promise<User>.
•
await розкриває Promise.
•
Обробляй помилки через try/catch.
•
Не повертай any з async-ланцюгів.
Що таке overloads (перевантаження) функцій?
•
Можна оголосити кілька сигнатур.
•
Реалізація одна, але типи різні.
•
Корисно для функцій з різними режимами.
•
Перевантаження мають бути сумісними.
•
Іноді простіше використовувати union і narrowing.
Чим відрізняється type assertion (as) від реальної перевірки типів?
•
as не перевіряє runtime.
•
Він каже компілятору: 'повір'.
•
Може приховати баги.
•
Краще спочатку валідовувати дані.
•
Використовуй as тільки коли точно знаєш структуру.
Що таке non-null assertion (!) і чому він небезпечний?
•
x! говорить, що x не null/undefined.
•
Компилятор перестає скаржитись.
•
В runtime може впасти, якщо ти помилився.
•
Краще перевірка if (x) або optional chaining.
•
Використовуй рідко і усвідомлено.
Як працює optional chaining (?.)?
•
Дозволяє безпечно звертатися до вкладених полів.
•
obj?.a?.b поверне undefined, якщо щось відсутнє.
•
Працює з викликом функцій: fn?.().
•
Не замінює бізнес-валидацію.
•
Зручно для UI та даних з API.
Як працює nullish coalescing (??)?
•
a ?? b бере b тільки якщо a null/undefined.
•
Не плутати з 0/''/false як ||.
•
Відмінно для дефолтів.
•
Часто комбінують з optional chaining.
•
Розумій різницю між || і ??.
Як типізувати помилки в catch у строгому режимі?
•
В TS catch-перемінна часто unknown.
•
Перевір: err instanceof Error.
•
Логуй безпечно: String(err).
•
Для бібліотек роби свої типи помилок.
•
Не передбачай структуру без перевірки.
Що таке discriminated union і як його проектувати?
•
Union з полем-тегом: type: 'a' | 'b'.
•
У switch по тегу тип автоматично звужується.
•
Зручно для подій і стану.
•
Додавай exhaustive check (never).
•
Це один із кращих патернів TS.
Як зробити exhaustive check у switch?
•
У default присвой змінну типу never.
•
Якщо з’явиться новий варіант union — компілятор скаржитиметься.
•
Приклад: const _exhaustive: never = x.
•
Допомагає підтримувати код.
•
Особливо корисно в reducer'ах.
Як типізувати класи та їх поля у TypeScript?
•
Вказуй модифікатори: public/private/protected.
•
Оголошуй поля заздалегідь або в constructor.
•
Використовуй readonly для незмінних.
•
Параметр-властивість: constructor(private api: Api) {}.
•
Не зловживай класами, якщо достатньо функцій.
Що таке abstract class і interface: що обрати?
•
interface описує контракт без реалізації.
•
abstract class може містити спільну реалізацію.
•
У TS можна реалізувати кілька interface, але успадковувати один клас.
•
Для 'портів' та API зазвичай достатньо interface.
•
Abstract зручний для базових компонентів/шаблонів.
Як типізувати this у методах і функціях?
•
У методів класів this виводиться автоматично.
•
Для функцій можна вказати this-параметр: function f(this: X) {}.
•
Стрілкові функції беруть this із зовнішнього контексту.
•
У callbacks часто втрачається this — біндуй або використовуй стрілки.
•
Правильна типізація ловить помилки.
Як працює enum і чому часто радять union замість enum?
•
enum генерує runtime-код (зазвичай).
•
Може ускладнити bundle.
•
Union літералів простіше і tree-shakable.
•
Якщо потрібно runtime-значення — можна enum або const object.
•
const enum прискорює, але небезпечний для бібліотек.
Що таке const enum і в чому його ризики?
•
const enum інлайниться у код.
•
Зменшує runtime-накладні.
•
Може ламатися при збірці бібліотек і різних налаштуваннях.
•
Не завжди сумісний з babel/transpileOnly.
•
Часто краще об'єкт + as const.
Як типізувати функції вищого порядку (HOF)?
•
Обґрунтовуй вхідний і вихідний тип.
•
Зберігай сигнатуру через generics.
•
Для декораторів функцій використовуй <T extends (...a: any[]) => any>.
•
Повертай Parameters<T> і ReturnType<T>.
•
Це дає сильну типізацію.
Що таке ReturnType і Parameters і коли вони потрібні?
•
ReturnType<F> бере тип результату функції.
•
Parameters<F> бере кортеж аргументів.
•
Корисно для обгорток і проксі.
•
Знижує дублювання.
•
Працює тільки з типами функцій.
Як типізувати систему подій (event emitter) безпечно?
•
Зроби map: EventName -> payload type.
•
on<K extends keyof Events>(name: K, cb: (p: Events[K]) => void).
•
emit аналогічно.
•
Так ти уникнеш помилок типів у подіях.
•
Гарний патерн для фронту і ноди.
Як типізувати API-клієнт і відповіді сервера?
•
Визнач DTO типи для відповідей.
•
Використовуй runtime-валидацію для зовнішніх даних.
•
Для fetch роби функцію request<T>() що повертає Promise<T>.
•
Ніколи не довіряй серверу без перевірок.
•
Логуй і обробляй помилки статусів.
Як типізувати fetch і обробку JSON?
•
const res = await fetch(url).
•
Перевіряй res.ok.
•
const data: unknown = await res.json().
•
Валідируй data і потім приведи до типу.
•
Таймаути/ретраї додавай окремо.
Як у TS правильно працювати з DOM-типами?
•
Включи lib: ['DOM'].
•
Використовуй querySelector з generic: document.querySelector<HTMLDivElement>('...').
•
Перевіряй на null.
•
Для подій використовуй MouseEvent/KeyboardEvent.
•
Не кастуй без необхідності.
Як типізувати addEventListener і обробники?
•
element.addEventListener('click', (e) => { ... }).
•
e має тип MouseEvent (для кліка).
•
Для window/document типи теж виводяться.
•
Якщо потрібно, уточнюй target через instanceof.
•
Не використовуй any для подій.
Як типізувати React-компоненти на TypeScript?
•
Props через interface/type.
•
function Component(props: Props) { ... }.
•
Для children: React.ReactNode.
•
Для подій: React.ChangeEvent<HTMLInputElement>.
•
Не завжди потрібен React.FC.
Коли використовувати React.FC, а коли ні?
•
React.FC додає children за замовчуванням.
•
Іноді це небажано.
•
Типізація defaultProps відрізняється.
•
Прості функції з Props зазвичай достатньо.
•
Обирай єдиний стиль у проекті.
Як типізувати useState у React?
•
useState<number>(
•
фіксує тип.
•
Для nullable: useState<User | null>(null).
•
Для складних об'єктів краще інтерфейс.
•
Лінива ініціалізація: useState(() => compute()).
•
Уникай any у стані.
Як типізувати useRef?
•
useRef<HTMLDivElement | null>(null).
•
Перевіряй ref.current на null.
•
Для mutable значення: useRef<number>(0).
•
Не використовуй ref як стан.
•
Для callbacks можна useCallback ref.
Що таке declaration merging і де воно зустрічається?
•
interface може об'єднуватися за ім'ям.
•
Зручно для розширення глобальних типів.
•
Часто використовується для доповнення Window/NodeJS.ProcessEnv.
•
Може бути джерелом конфліктів.
•
Контролюй, де оголошуєш глобальні типи.
Як розширити тип Window або ProcessEnv?
•
Створи d.ts файл у проекті.
•
declare global { interface Window { ... } }.
•
Для env: declare namespace NodeJS { interface ProcessEnv { ... } }.
•
Не забудь export {} у файлі.
•
Слідкуй, щоб include бачив цей файл.
Що таке .d.ts файли і навіщо вони потрібні?
•
Це файли декларацій типів.
•
Потрібні для JS-бібліотек без типів.
•
Можуть описувати API без реалізації.
•
Використовуються DefinitelyTyped (@types/*).
•
Підключаються через types/include.
Як додати типи для JS-бібліотеки без @types?
•
Спочатку перевір, чи немає вбудованих типів.
•
Якщо ні — створи мінімальний .d.ts з declare module 'lib'.
•
Постепенно уточнюй типи за мірою використання.
•
Можна написати wrapper API зі строгими типами.
•
Для складних випадків — генерація з OpenAPI/JSON schema.
Що таке moduleResolution і коли його змінювати?
•
Визначає, як TS шукає модулі.
•
NodeNext потрібен для ESM/Node 16+.
•
Bundler підходить для Vite/webpack.
•
Classic майже не потрібен.
•
Вибір залежить від рантайму та збірщика.
Як налаштувати алиаси шляхів (paths) у tsconfig?
•
Вкажи baseUrl.
•
Додай paths: { '@/*': ['src/*'] }.
•
Налаштуй збірщик (webpack/vite) аналогічно.
•
Налаштуй jest/vitest алиаси теж.
•
Інакше в runtime алиаси не працюватимуть.
Чому TS проходить, а в runtime модуль не знаходиться?
•
TS перевіряє шляхи за tsconfig paths.
•
Але Node/бандлер може не знати про алиаси.
•
Потрібно налаштувати резолвер у збірщику/тестах.
•
Для Node можна використовувати tsconfig-paths.
•
Завжди перевіряй конфігурацію runtime.
Що таке isolatedModules і коли він потрібен?
•
Потрібен для transpile через Babel/'один файл'.
•
Забороняє деякі конструкції (наприклад, const enum).
•
Допомагає сумісності зі збірщиками.
•
У Next.js зазвичай вмикають.
•
Краще тримати увімкненим у фронтенд-проектах.
У чому різниця між tsc і babel/swc при збірці TS?
•
tsc виконує типову перевірку і може емитити JS.
•
Babel/SWC швидко транспілюють, але не перевіряють типи.
•
У таких схемах типчек запускають окремо (tsc --noEmit).
•
Next/Vite часто використовують SWC/Babel.
•
Перевірка типів потрібна в CI.
Як увімкнути перевірку типів без генерації JS?
•
Запусти: tsc --noEmit.
•
Або постав noEmit: true в tsconfig.
•
Зручно для проектів, де збірку робить інший інструмент.
•
В CI роби окремий крок typecheck.
•
Помилки типів тоді не потраплять у прод.
Що таке source maps і як вони допомагають?
•
Пов’язують скомпільований JS із вихідним TS.
•
Спрощують відладку в браузері і Node.
•
Вмикається sourceMap: true.
•
У проді іноді відключають через розмір і безпеку.
•
Для Sentry корисні.
Як правильно типізувати конфіг-об’єкти?
•
Використовуй const + as const для літералів.
•
Для перевірки структури застосовуй satisfies.
•
Уникай any.
•
Зберігай конфіг у одному місці, не розмазуй.
•
Для env-змінних роби явне перетворення типів.
Як типізувати process.env і позбавитись 'string | undefined'?
•
В runtime змінні можуть відсутні.
•
Спершу валідируй наявність (наприклад, через функцію requireEnv).
•
Після перевірки можна повернути string.
•
Краще робити єдиний шар конфігурації.
•
Для строгої схеми використовуй zod/valibot.
Як типізувати функцію, яка кидає помилку (never)?
•
Функції, що завжди кидають/завершують процес, повертають never.
•
Приклад: function fail(msg: string): never { throw new Error(msg) }.
•
Зручно в exhaustive checks.
•
Допомагає аналізу потоку.
•
Покращує читабельність помилок.
Що таке типи шаблонних літералів?
•
Типи рядків із шаблоном: `user:${string}`.
•
Корисно для побудови ключів і маршрутів.
•
Працюють з union і mapped types.
•
Ускладнюють типи, використовуйте обережно.
•
Відмінно для подій/ID-шників.
Як типізувати рядки формату UUID/id?
•
Повної валідації типами зробити не можна.
•
Можна створити брендований тип: type UUID = string & { __brand: 'UUID' }.
•
Перетворення лише після перевірки regex.
•
Це підвищує безпеку API.
•
Без runtime перевірки бренд безглуздо.
Що таке branded types і навіщо вони потрібні?
•
Це спосіб розрізняти однакові примітиви (string vs Email).
•
Робиться через перетин із 'маркером'.
•
Вимагає фабрики/валідації.
•
Зменшує помилки при передачі параметрів.
•
Корисно в доменній моделі.
Як типізувати функції-валідатори?
•
Повертають boolean і type predicate.
•
Наприклад: (x: unknown): x is User.
•
Тримай перевірки на одному рівні, без side effects.
•
Валідація схемою часто простіша.
•
Додай тести на валідатори.
Що таке conditional types?
•
Типи виду T extends U ? X : Y.
•
Використовуються для розумних утиліт.
•
Можуть розподілятися по union.
•
Іноді сильно сповільнюють компіляцію.
•
Застосовуй переважно для бібліотечного коду.
Що таке infer у conditional types?
•
infer дозволяє 'витягнути' частину типу.
•
Наприклад, отримати тип елемента масиву.
•
Використовується в ReturnType/Parameters.
•
Потужно, але важче читати.
•
Пиши приклади і тестуй типи.
Як отримати тип елемента масиву (array element type)?
•
Для масиву T[] елемент — T.
•
Для довільного: type Elem<A> = A extends (infer T)[] ? T : never.
•
Для readonly масивів враховуй readonly.
•
Корисно в узагальнених утилітах.
•
Не забувай про tuple.
Що таке utility types Required/Readonly і навіщо?
•
Required робить поля обов’язковими.
•
Readonly робить поля тільки для читання.
•
Використовуй для публічних інтерфейсів і імутабельності.
•
Є ReadonlyArray і readonly tuple.
•
Зменшує кількість мутацій у коді.
Як типізувати partial update об’єкта безпечно?
•
Не роби Partial<T> на все підряд.
•
Обмеж набір полів: Partial<Pick<T, 'a' | 'b'>>.
•
Для заборони деяких полів — Omit.
•
Валідируй дані перед застосуванням.
•
Для API краще окремий DTO.
Як типізувати функцію merge без втрати типів?
•
<A extends object, B extends object>(a: A, b: B): A & B.
•
Але враховуй конфліктуючі ключі.
•
В runtime застосовуй Object.assign/spread.
•
Для глибокого merge типи складніші.
•
Іноді краще явний опис результату.
Як працювати з readonly і мутаціями об'єктів?
•
Readonly забороняє присвоювання полям.
•
Для змін створіть копію через {...obj}.
•
Для масивів: [...arr].
•
Використовуйте імутабельні патерни у стані.
•
Для глибоких структур потрібна дисципліна/immer.
Як типізувати об'єкт, який може бути null?
•
Використовуйте union: T | null.
•
Перевіряйте if (x == null) return.
•
Уникайте ! для обходу.
•
Для ланцюгового доступу використовуйте ?.
•
Продумайте, де саме допускається null.
Як правильно обрати між null і undefined?
•
undefined частіше означає 'відсутність значення' за замовчуванням.
•
null часто використовується як явне 'порожньо'.
•
Тримайте єдиний стиль у проекті.
•
В API краще документувати.
•
У strictNullChecks обидва вимагають обробки.
Як типізувати функції з опційними параметрами?
•
Параметр: foo(x?: string).
•
Або foo(x: string | undefined).
•
Враховуйте, що x може бути undefined.
•
Встановлюйте дефолт: function foo(x: string = 'a').
•
Не робіть багато опційних підряд — краще об'єкт параметрів.
Як типізувати 'options object' замість довгого списку аргументів?
•
Створіть interface Options { ... }.
•
function f(opts: Options) {}.
•
Надання дефолтів через деструктуризацію.
•
Це зручніше для розширення API.
•
Дозволяє робити Partial<Options> для дефолтів.
Як працює структурне типізування в TypeScript?
•
В TS важлива структура, а не ім'я типу.
•
Два типи сумісні, якщо поля збігаються.
•
Це зручно, але може приховати помилки у домені.
•
Branded types допомагають розрізняти.
•
Завжди думайте про межі системи.
Що таке номінальне типізування і як імітувати його в TS?
•
Номінальне — сумісність за ім'ям типу.
•
В TS можна імітувати через бренди.
•
type UserId = string & { __brand: 'UserId' }.
•
Створіть функцію-конструктор після валідації.
•
Це зменшує випадкові підстановки.
Як типізувати функції роботи з масивами (map/filter/reduce) без any?
•
TS автоматично виводить типи колбеків.
•
Слідкуйте, щоб вихідний масив був типізований.
•
Для reduce вказуйте початкове значення і тип акумулятора.
•
Уникайте reduce без initial — можуть виникнути проблеми.
•
Для filter іноді потрібен type guard.
Як зробити type guard для filter?
•
Приклад: const isDefined = <T>(x: T | undefined): x is T => x !== undefined.
•
Тоді arr.filter(isDefined) видалить undefined.
•
Аналогічно для null.
•
Зручно у пайплайнах даних.
•
Створюйте такі утиліти в одному місці.
Що таке satisfies для масивів і словників?
•
Можна перевірити тип масиву, не втрачаючи literal types.
•
Приклад: const routes = [...] satisfies Route[].
•
Компилятор перевірить структуру елементів.
•
Але збереже конкретику значень.
•
Гармонійний баланс між 'як є' і строгим перевіркою.
Як прискорити компіляцію TypeScript у великому проекті?
•
Увімкни incremental.
•
Використовуй project references.
•
Зменшуй include і виключи build/output папки.
•
Уникай складних conditional types у гарячих місцях.
•
Онови TS до актуальної версії.
Що таке project references і навіщо вони потрібні?
•
Це розбиття монорепо на проекти TS.
•
Прискорює збірку і typecheck.
•
Дозволяє 'інкрементально' перевіряти лише змінені частини.
•
Вимагає composite: true.
•
Добре для великих кодових баз.
Як налаштувати monorepo з TypeScript?
•
Використовуй менеджер workspace (pnpm/yarn/npm).
•
Створи базовий tsconfig і наслідуйся від нього.
•
Увімкни project references.
•
Слідкуй за єдиними версіями TS і типів.
•
Налаштуй лінтер і форматтер однаково.
Як правильно типізувати публічний API бібліотеки?
•
Експортуй лише потрібні типи.
•
Не експортуй внутрішні деталі.
•
Стабілізуй contract і версіонуй.
•
Генеруй d.ts (declaration: true).
•
Тестуй типи через dtslint або tsd.
Як перевірити типи у CI?
•
Додай скрипт: npm run typecheck.
•
Запускай tsc --noEmit.
•
Окремо запускай eslint/test.
•
Не покладайся на IDE.
•
Зроби перевірку обов’язковою перед merge.
Як типізувати проект Node.js на TypeScript?
•
Налаштуй module і moduleResolution під ESM/CJS.
•
Додай @types/node.
•
Обери раннер: ts-node, tsx або збірку через tsc.
•
Слідкуй за шляхами/аліасами.
•
Перевір запуск у проді (без ts-node).
У чому різниця між ESM і CommonJS у контексті TypeScript?
•
ESM використовує import/export у runtime.
•
CJS використовує require/module.exports.
•
TS може емитити обидва варіанти.
•
У Node важливі package.json type і розширення .mts/.cts.
•
Помилки частіше через змішування систем.
Як налаштувати TypeScript для Node ESM (NodeNext)?
•
module: NodeNext і moduleResolution: NodeNext.
•
У package.json постави type: module.
•
Використовуй розширення/exports правильно.
•
Для типів можна .d.ts або .mts.
•
Перевір збірку і запуск разом.
Як типізувати Express middleware?
•
Встанови @types/express.
•
Типи Request, Response, NextFunction.
•
Розширюй Request через declaration merging, якщо додаєш поля.
•
Робіть явні типи для body/query/params.
•
Валідовуй вхідні дані.
Як типізувати DTO і валідацію вхідних даних?
•
Типи TS не валідовують runtime.
•
Використовуй zod/yup/class-validator.
•
Схема має бути джерелом істини.
•
Генеруй тип із схеми, якщо бібліотека дозволяє.
•
Тримай валідатор на межі системи (API).
Як безпечно працювати з зовнішніми даними: JSON, API, localStorage?
•
Вважайте все зовнішнє як unknown.
•
Валідовуйте структуру (schema/type guards).
•
Обробляйте відсутність полів і версії.
•
Логуйте помилки парсингу та фолбеки.
•
Не використовуйте as без перевірок.
Як типізувати localStorage і перетворення типів?
•
localStorage зберігає рядки.
•
Створюйте функції getJSON<T>() з unknown + валідатором.
•
Для чисел/булевих — явне перетворення.
•
Обробляйте відсутність ключа.
•
Версіонізуйте формат збереження.
Як правильно типізувати помилки для доменної логіки?
•
Створюйте свої класи помилок (extends Error).
•
Додавайте код/тип причини.
•
Ловіть і маппіть у верхньому шарі (API/UI).
•
Не кидайте рядками.
•
Документуйте, які помилки можливі.
Які типові антипатерни в TypeScript слід уникати?
•
any і ланцюжки as as.
•
! замість перевірок.
•
Складні типи заради типів без вигоди.
•
Дублювання DTO замість утиліт Pick/Omit.
•
'Магія' в типах без тестів і прикладів.
Як писати підтримувані типи: практичні правила?
•
Спочатку прості типи, ускладнюйте за потреби.
•
На межах системи валідовуйте runtime.
•
Не приховуйте проблему через any/as.
•
Використовуйте discriminated unions для станів.
•
Підтримуйте єдиний стиль і типчекі в CI.
TypeScript — Програмування — Технології — FAQ Портал