Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Senior: питання на співбесіді з теми «Конфігурація й інструменти»

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

4 питання

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

Що це дає на практиці:

  • повна збірка у 8-12 разів швидша: за даними команди TypeScript, перевірка кодової бази VS Code - 10,6 с замість 125,7 с;
  • редактор: проєкт відкривається й показує першу помилку за секунду-дві замість десятків секунд;
  • пам'ять - зазвичай менше, ніж у TypeScript 6;
  • новий режим --watch на основі файлового спостерігача з Parcel, портованого на Go.

Нові прапорці паралелізму:

  • --checkers N - кількість паралельних перевіряльників типів (за замовчуванням 4). Більше - швидше на потужних машинах, але більше пам'яті; на слабких CI-раннерах варто зменшити;
  • --builders N - паралельна збірка проєктів у --build (монорепозиторії). Множиться з --checkers: 4 × 4 - до 16 перевіряльників одночасно;
  • --singleThreaded - вимкнути паралелізм (налагодження, обмежені середовища).

Різна кількість --checkers у рідкісних випадках може дати різні результати, залежні від порядку, - тому команді варто зафіксувати одне значення для всіх середовищ.

Що потребує уваги при переході:

  • TypeScript 7 бере значення за замовчуванням з 6.0 (strict, types: [], rootDir: ".") і робить помилками все, що 6.0 оголосив застарілим: baseUrl, moduleResolution: node10, target: es5, module: amd/umd, esModuleInterop: false та інше. Рекомендований шлях - спершу перейти на 6.0 і прибрати всі попередження;
  • немає програмного API в 7.0 - його обіцяють у 7.1. Інструменти, що імпортують typescript як бібліотеку (typescript-eslint, частина плагінів збирачів), працюють через пакет сумісності @typescript/typescript6, встановлений поряд через псевдонім npm. Тоді tsc - це TypeScript 7, а інструменти бачать API 6.0;
  • JSDoc у JavaScript-файлах аналізується ближче до .ts - деякі старі шаблони перестали розпізнаватися;
  • шаблонні рядкові типи тепер працюють з кодовими точками Unicode, а не з половинками сурогатних пар.

Що лишилося незмінним: мова, синтаксис і правила перевірки. Код, що компілюється в 6.0 без попереджень, компілюється в 7.0 так само.

Докладніше в документації: Анонс TypeScript 7.0

Сучасний Node.js виконує .ts-файли без окремої збірки: він замінює анотації типів пробілами (type stripping) і запускає те, що лишилося.

node scripts/import-vacancies.ts

Зняття типів увімкнене за замовчуванням з Node.js 22.18 / 23.6 і стабільне з 24.12 / 25.2. Перевірки типів при цьому немає - помилки типів не зупинять запуск.

Обмеження - лише «стиранний» синтаксис. Node.js не генерує код, він тільки прибирає типи. Конструкції TypeScript, що створюють JavaScript, не підтримуються:

  • enum;
  • namespace з кодом під час виконання;
  • параметри-властивості в конструкторі (constructor(private repo: Repo));
  • import x = require(...) і псевдоніми імпорту;
  • декоратори (поки їх немає в самому JavaScript).

Прапорець --experimental-transform-types, що їх перетворював, у Node.js 26 прибрали.

erasableSyntaxOnly (з TypeScript 5.8) змушує tsc повідомляти про такі конструкції заздалегідь:

enum Status { Draft, Published }   // error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled

Замість enum - об'єкт з as const і тип-об'єднання; замість параметрів-властивостей - звичайні поля.

Рекомендовані Node.js налаштування tsconfig.json:

{
  "compilerOptions": {
    "noEmit": true,
    "target": "esnext",
    "module": "nodenext",
    "rewriteRelativeImportExtensions": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true
  }
}

Інші особливості:

  • розширення обов'язкові: import { x } from './utils.ts';
  • import type для типів - інакше Node.js залишить імпорт і впаде (тому verbatimModuleSyntax);
  • tsconfig.json ігнорується: paths не працюють - замість них subpath imports у package.json ("#/*");
  • файли в node_modules не виконуються - пакети мають публікуватися як JavaScript;
  • .tsx не підтримується.

Коли це доречно: скрипти, утиліти, інструменти розробки, невеликі сервіси - там, де збірка була зайвим кроком. Для повної підтримки TypeScript (paths, enum, JSX) - інструменти на кшталт tsx або звичайна збірка.

Докладніше в документації: Node.js: TypeScript

Великий кодовий масив в одному tsconfig.json перевіряється цілком при кожній зміні. Project references ділять його на окремі проєкти з явними залежностями, і TypeScript перевіряє лише змінене та залежне від нього.

Структура:

// tsconfig.json (корінь) - лише посилання
{
  "files": [],
  "references": [
    { "path": "./packages/shared" },
    { "path": "./packages/web" },
    { "path": "./packages/admin" }
  ]
}

// packages/shared/tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "rootDir": "./src",
    "outDir": "./dist"
  }
}

// packages/web/tsconfig.json
{
  "references": [{ "path": "../shared" }]
}
tsc -b            # зібрати всі проєкти в порядку залежностей
tsc -b --watch

composite: true - вимоги до проєкту, на який посилаються: генерація .d.ts, явний rootDir, усі файли в include. Залежний проєкт бачить лише оголошення (.d.ts) залежності, а не її вихідний код - тому перевірка швидша.

incremental - зберегти результати попередньої перевірки у файлі .tsbuildinfo і наступного разу перевіряти лише змінене. Для composite увімкнено автоматично.

Що це дає:

  • швидкість: зміна в admin не змушує перевіряти web;
  • межі: пакет не може імпортувати з іншого, якщо на нього немає посилання, - архітектура перевіряється компілятором;
  • різні налаштування для частин: код браузера з lib: ["dom"], конфіги й сервер - з типами Node.js. Саме так шаблон Vite ділить проєкт на tsconfig.app.json і tsconfig.node.json.

TypeScript 7 збирає незалежні проєкти паралельно (прапорець --builders), тож виграш від поділу ще більший. Обмежувач - граф залежностей: проєкт збирається лише після тих, від яких залежить. Опція isolatedDeclarations дає змогу генерувати .d.ts без перевірки типів залежностей і розпаралелити й це.

Пастки:

  • rootDir з TypeScript 6.0 за замовчуванням - каталог з tsconfig.json. Якщо вихідні файли в src/, а rootDir не вказано, результат опиниться в dist/src/... замість dist/...;
  • застарілі .d.ts: редактор може показувати старі типи залежності, доки її не перезібрано;
  • skipLibCheck (пропустити перевірку .d.ts) теж помітно пришвидшує збірку, але ховає помилки в оголошеннях власних пакетів - його вмикають свідомо.

Докладніше в документації: Project references

TypeScript 6.0 - перехідний реліз: останній на старому компіляторі, який готує проєкти до TypeScript 7. Він змінює значення за замовчуванням і оголошує застарілими опції, які в 7.0 стали помилками.

Нові значення за замовчуванням:

Опція Було Стало
strict false true
module залежно від target esnext
target es5 останній стабільний стандарт (es2025)
types усі @types/* []
rootDir спільний каталог вихідних файлів каталог з tsconfig.json
noUncheckedSideEffectImports false true

Найчастіші проблеми після оновлення:

  • «Cannot find name 'process'» / «describe» - додати "types": ["node", ...];
  • результат збирається в dist/src/index.js замість dist/index.js - вказати "rootDir": "./src";
  • нові помилки строгості - або виправляти, або явно "strict": false як тимчасовий крок.

Видалено в TypeScript 7 (у 6.0 - попередження, які можна приглушити "ignoreDeprecations": "6.0"):

  • baseUrl - шляхи в paths тепер відносно каталогу конфігу з префіксом ./;
  • moduleResolution: node (node10) і classic - замінити на bundler або nodenext;
  • target: es5 і downlevelIteration - найнижча ціль es2015; для ES5 - зовнішній компілятор;
  • module: amd, umd, systemjs, none і outFile;
  • esModuleInterop: false, allowSyntheticDefaultImports: false, alwaysStrict: false;
  • ключове слово module для просторів імен (лише namespace) і asserts в імпортах (лише with);
  • передача файлів у tsc у каталозі з tsconfig.json без --ignoreConfig.

Рекомендований порядок:

  1. оновитися до TypeScript 6.0 і виправити всі попередження про застарілі опції (не приглушувати ignoreDeprecations надовго - у 7.0 це не спрацює);
  2. частину змін (baseUrl, rootDir) робить автоматично експериментальний інструмент ts5to6;
  3. перевірити з прапорцем stableTypeOrdering - у 7.0 він увімкнений і незмінний; з ним 6.0 дає ті самі результати, що й 7.0;
  4. перейти на TypeScript 7, а для інструментів, що потребують API (typescript-eslint), лишити поряд @typescript/typescript6.

Чому ці зміни корисні: явний types пришвидшує перевірку на 20-50%, а видалені опції здебільшого ховали помилки (TypeScript «бачив» імпорти, які не працювали під час виконання).

Докладніше в документації: Анонс TypeScript 6.0