#17 - Налаштування tsconfig, оптимізація, підключення до front-end так бек проектів

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

Основи tsconfig:

Це основні налаштування, які завжди присутні в базовій версіі tsconfig

{
  "compilerOptions": { ... }, // Параметри компілятора
  "include": ["src"],         // Які файли включати
  "exclude": ["node_modules"],// Які файли виключити
  "files": ["src/index.ts"],  // Які файли явно включити
  "references": [ ... ]       // Для проектів з розділенням (Project References)
}

compilerOptions

По більшій мірі основними являються - налаштування компілятора. Це обʼєкт, в якому зберігаютьс явсі налаштування компілятора, ми розберемо основні, та часто використовуємі:

Target & Module

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

  • target: ES5, ES6, ES2017, ES2020, ESNext
  • module: CommonJS, ESNext, UMD, AMD, System
{
  "compilerOptions": {
     "target": "ES2020",         // JS-стандарт на виході
     "module": "ESNext",         // Формат модулів
  }
}

Strickness

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

{
  "compilerOptions": {
    // 🔒 Вмикає суворий режим типізації — еквівалентно вмиканню всіх нижченаведених опцій
    "strict": true,

    // 🚫 Забороняє неявне використання типу "any"
    // Якщо TypeScript не може вивести тип — видає помилку
    "noImplicitAny": true,

    // ❗️Забороняє використання null або undefined без перевірки
    // Наприклад: функції можуть явно повертати null, але використання має перевірятися
    "strictNullChecks": true,

    // 🧠 Більш сувора перевірка типів функцій, особливо при присвоєнні функцій змінним
    // Наприклад, уникає проблем з "неповними" сигнатурами
    "strictFunctionTypes": true,

    // 🔧 Контролює типи аргументів при використанні call, bind, apply
    // Допомагає уникнути помилок при викликах з контекстом
    "strictBindCallApply": true,

    // ✅ Увімкнення суворого режиму JS (`'use strict'`) у кожному файлі
    "alwaysStrict": true,

    // ⚠️ Забороняє використання `this` без явного контексту
    // Наприклад, в методах або функціях, де `this` може бути undefined
    "noImplicitThis": true,

    // 🕵️‍♂️ Вимагає явно вказувати тип змінної у `catch`
    // Замість `catch (err)`, потрібно `catch (err: unknown)`
    "useUnknownInCatchVariables": true
  }
}

Якщо ти вказуєш "strict": true, то всі ці опції автоматично активуються. Але ти також можеш вимикати окремі з них вручну, якщо потрібно.

{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": false // дозволити any тільки для прототипів
  }
}

Module Resolution

Ці параметри вирішують де будуть лежати типи, які типи підтягувати, які аліаси використовувати

{
  "compilerOptions": {
     "moduleResolution": "node",    // або "classic"
     "baseUrl": ".",                              // Базовий шлях
     "paths": {
       "@components/*": ["src/components/*"]   // створюють псевдоніми для імпорт (аліаси)
     },
     "rootDirs": ["src", "generated"],   // які папки взагалі будуть оброблятися
     "typeRoots": ["node_modules/@types"],     // де шукати типи
     "types": ["node", "jest"]         // які типи підтягувати (Jest, Node, Web)
   }
}

Output Control

Як зрозуміло з назви, ця група параметрів відповідає за шляхи збереження та обробки

{
  "compilerOptions": { 
     "outDir": "dist",     // Куди зберігати компільований код
     "rootDir": "src",     // Де шукати вхідні файли
     "declaration": true,  // Створювати *.d.ts файли
     "declarationMap": true, // Створювати sourcemap
     "sourceMap": true,    // Створювати *.map для дебагу
     "removeComments": true, // видаляти коментарі з коду
     "noEmit": false,      // Не створювати JS-файли
     "emitDeclarationOnly": false // виводити лише .d.ts файли (типи), без .js коду.
   }
}

JS Compatibility

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

{
  "compilerOptions": {
    "allowJs": true,                   // Дозволяє включати у проєкт `.js` файли разом з `.ts` — корисно при міграції з JavaScript
    "checkJs": true,                   // Вмикає перевірку типів у `.js` файлах (якщо `allowJs` також увімкнено)
    "esModuleInterop": true,          // Дозволяє імпортувати CommonJS-модулі (типу `const x = require(...)`) як `import x from '...'`. Автоматично додає `__importDefault` трансформацію для сумісності з ES-модулями
    "allowSyntheticDefaultImports": true, // Дозволяє використовувати синтетичний `import defaultExport from "..."`, навіть якщо модуль не має експорту за замовчуванням. НЕ змінює вихідний JS-код, лише впливає на перевірку типів
    "resolveJsonModule": true,        // Дозволяє імпортувати `.json` файли як модулі (типу: `import data from './data.json'`)
    "isolatedModules": true,          // Вимагає, щоб кожен файл міг бути скомпільований окремо. Обов’язкова опція для проєктів на Vite, Next.js, або Babel (без повної підтримки TS)
    "downlevelIteration": true,       // Додає підтримку `for...of`, spread (`...`) і деструктуризацію для старих JS-версій (`ES5`). Наприклад: `for (const item of arr)` буде працювати навіть у `target: ES5`
    "lib": ["ES2020", "DOM", "DOM.Iterable"] // Вказує, які вбудовані бібліотеки підключити:
                                             // - `ES2020`: методи з ECMAScript 2020 (наприклад `Promise.allSettled`)
                                             // - `DOM`: об'єкти браузера (window, document тощо)
                                             // - `DOM.Iterable`: дозволяє ітерувати DOM-колекції (типу `NodeList`)
  }
}

Code Quality / Control

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

{
  "compilerOptions": {
    "noFallthroughCasesInSwitch": true,   // Забороняє "провалювання" між case'ами в switch без break
                                          // Наприклад, помилка якщо в одному case немає break, return або throw:
                                          // ❌ case 1: ...; // випадково переходить у case 2
                                          // ✅ case 1: ...; break;

    "noImplicitReturns": true,            // Попереджає, якщо не всі гілки функції повертають значення
                                          // Це запобігає багам, де функція неявно повертає undefined

    "noUnusedLocals": true,               // Генерує помилку, якщо є змінні, які оголошені, але ніде не використовуються
                                          // Це допомагає утримувати код чистим і без сміття

    "noUnusedParameters": false,          // Якщо true — генерує помилку, якщо параметри функції не використовуються
                                          // Вимикають у випадках, коли хочеш залишити сигнатуру заради API, але не використовуєш параметри
                                          // Наприклад: `function log(_: string) {}` — параметр не використовується, але залишений

    "forceConsistentCasingInFileNames": true, // Вимагає, щоб регістр літер у шляхах імпорту збігався з назвою файлу на файловій системі
                                               // Наприклад: `import x from './MyFile'` => помилка, якщо файл називається `myfile.ts`

    "skipLibCheck": true                   // Пропускає перевірку типів у файлах типів бібліотек (`*.d.ts`)
                                          // Значно пришвидшує компіляцію, особливо у великих проєктах
                                          // Рекомендується увімкнути, якщо не розробляєш саму бібліотеку
  }
}

Також не дуже часті, але теж зустрічаємі параметри:

{
  "compilerOptions": {
    // ❌ Якщо під час компіляції знайдено помилки — не генерувати жодного JS-файлу
    // Захищає від того, щоб випадково не запустити або не задеплоїти битий код
    "noEmitOnError": true,

    // 🎯 Типи для опціональних властивостей будуть точними
    // Наприклад: `foo?: string` не дозволяє `undefined | string` без додаткової перевірки
    "exactOptionalPropertyTypes": true,

    // 🚫 Заборонити недосяжний код (після return, throw і т.д.)
    // Наприклад: `return; console.log('hello')` — помилка
    "allowUnreachableCode": false,

    // 🚫 Заборонити невикористані мітки (labels), як-от у `break myLabel`
    // Якщо мітка не використовується — буде помилка
    "allowUnusedLabels": false,

    // 📏 Визначає, як ініціалізуються поля в класах
    // true: поля ініціалізуються як `Object.defineProperty`, згідно з останнім стандартом
    // false: як звичайні властивості у JS
    "useDefineForClassFields": true
  }
}

на цьому поки що все.

Типові структури проєктів

Тепер, що до типових налаштувань для VUE.js проектів:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "jsx": "preserve",
    "moduleResolution": "Node",
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

Якщо ж ви використовуєте ще бекенд на ноді, тоді ще ось для беку:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "outDir": "dist",
    "rootDir": "src",
    "strict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

Часті помилки:

  • Cannot find module - Перевір baseUrl, paths, і розширення
  • ts-node не запускає код з import - Увімкни esModuleInterop
  • .json не імпортується - Додай resolveJsonModule
  • Бібліотека не має типів - Встанови @types/назва або створи *.d.ts