Junior: питання на співбесіді з теми «Конфігурація й інструменти»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
5 питань
tsconfig.json у корені проєкту каже компілятору TypeScript, які файли перевіряти і як це робити. Каталог з цим файлом вважається коренем проєкту.
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"target": "es2022",
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"noEmit": true,
"types": ["vite/client"],
"paths": { "@/*": ["./resources/js/*"] }
},
"include": ["resources/js/**/*.ts", "resources/js/**/*.vue"],
"exclude": ["node_modules", "public"]
}
Основні розділи:
include/exclude/files- які файли входять у проєкт.includeприймає шаблони,excludeвідкидає частину з них,files- явний список;compilerOptions- як перевіряти й що генерувати: строгість, цільова версія JavaScript, система модулів, шляхи, глобальні типи;extends- успадкувати базовий конфіг (свій спільний або з пакета на кшталт@tsconfig/strictest,@vue/tsconfig);references- посилання на інші проєкти в монорепозиторії.
Важливо розуміти, хто читає tsconfig.json:
tsc- повністю;- редактор (мовний сервер TypeScript) - для підказок і помилок;
- збирачі (Vite, esbuild) - лише частину опцій, і не перевіряють типи;
- Node.js з вбудованим зняттям типів - не читає взагалі.
noEmit: true - типова опція для застосунків на Vite: JavaScript генерує збирач, а tsc лише перевіряє типи.
Нові значення за замовчуванням (TypeScript 6.0+ і 7.0): strict увімкнено, module - esnext, target - останній стабільний стандарт ECMAScript, types - порожній список. Порожній tsconfig.json сьогодні - вже доволі строга конфігурація.
Практична порада: не копіювати чужий конфіг цілком, а починати з базового пресету фреймворку й змінювати лише те, що розумієте, - багато «магічних» опцій зі старих статей у TypeScript 7 уже видалено.
strict - не одна перевірка, а набір строгих опцій, увімкнених разом:
noImplicitAny- помилка, якщо тип не можна вивести і він став биany(параметри функцій без типів);strictNullChecks-nullіundefined- окремі типи.stringне може бутиnull, і компілятор змушує перевірити значення перед використанням. Найважливіша з усіх;strictFunctionTypes- коректна (контраваріантна) перевірка параметрів функцій;strictBindCallApply- перевірка аргументівbind,call,apply;strictPropertyInitialization- поля класу мають бути ініціалізовані в конструкторі;noImplicitThis- помилка наthisз неявним типомany;useUnknownInCatchVariables- змінна вcatchмає типunknown, а неany;alwaysStrict- режим'use strict'у кожному файлі (у TypeScript 7 його вже не можна вимкнути).
function greet(user: { name: string } | null) {
return user.name; // з strictNullChecks: помилка 'user' is possibly 'null'
}
З TypeScript 6.0 strict увімкнено за замовчуванням. Проєкт, що покладався на старе значення false, має явно вказати "strict": false - і це сигнал, що варто планувати перехід.
Чому не вимикати:
- без
strictNullChecksTypeScript мовчить про найпоширеніші помилки виконання -Cannot read properties of undefined; - без
noImplicitAnyзначна частина коду фактично не типізована; - нові опції строгості з'являються в наборі з новими версіями - проєкт зі
strict: trueотримує їх автоматично.
Міграція великого проєкту, де одразу тисячі помилок:
- вмикати опції по одній (
strict: false+ окремі прапорці), починаючи зnoImplicitAnyіstrictNullChecks; - або вмикати
strictдля нових каталогів через окремі конфіги чи інструменти поступової міграції.
Понад strict корисні noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitOverride, noFallthroughCasesInSwitch - вони в набір strict не входять і вмикаються окремо.
Ці три опції часто плутають, хоча вони відповідають на різні питання.
target - у яку версію JavaScript перетворювати синтаксис.
const user = data?.user ?? guest;
З target: "es2019" компілятор перепише ?. і ?? старим синтаксисом, з es2020 і новіше - лишить як є. target змінює лише синтаксис, а не додає відсутні функції (поліфіли).
У TypeScript 6.0+ значення за замовчуванням - останній стабільний стандарт (зараз es2025), а es5 у TypeScript 7 видалено - найнижча ціль тепер es2015. Для старих браузерів TypeScript-код компілюють іншим інструментом.
lib - які вбудовані API існують у середовищі, для перевірки типів:
"lib": ["es2025", "dom", "dom.iterable"]
Без dom компілятор не знає про document і window; без свіжого es20xx - про Array.prototype.toSorted чи Object.groupBy. Якщо lib не вказано, він береться з target (плюс dom). Для коду в Node.js dom зайвий, натомість потрібен пакет @types/node.
Пастка: lib лише описує типи. Вказати es2025, а запускати код у браузері, який цих методів не має, - помилка виконання, яку TypeScript не впіймає.
module - яку систему модулів генерувати (і як трактувати import/export):
esnext/preserve- лишити ES-модулі (типово для коду, який збирає Vite);nodenext- як Node.js: ES-модулі чи CommonJS залежно від"type"уpackage.jsonі розширень файлів;commonjs-require/module.exports.
amd, umd, systemjs і none у TypeScript 7 вже не підтримуються.
Пов'язана опція moduleResolution - як знаходити файли за шляхом в import: bundler для Vite, nodenext для коду, що виконує Node.js.
Для типового Vite-застосунку: target і module мало впливають на результат (код генерує збирач), але lib визначає, які API бачить редактор, - його варто узгодити з браузерами, які ви підтримуєте.
Замість import Button from '../../../components/Button.vue' зручно писати import Button from '@/components/Button.vue'. Для цього налаштовують псевдоніми шляхів.
У tsconfig.json:
{
"compilerOptions": {
"paths": {
"@/*": ["./resources/js/*"]
}
}
}
Важлива зміна: раніше разом з paths вказували baseUrl. У TypeScript 6.0 його оголосили застарілим, а в TypeScript 7 - видалено (помилка «Option 'baseUrl' has been removed»). Шляхи в paths тепер пишуть відносно каталогу з tsconfig.json, з явним префіксом ./.
Чому однієї опції paths замало: вона лише каже компілятору, де шукати типи. Код вона не змінює - у зібраному JavaScript лишиться import ... from '@/components/Button.vue', і хтось має перетворити цей шлях на справжній.
Тому той самий псевдонім треба налаштувати в інструменті, що виконує чи збирає код:
- Vite -
resolve.aliasуvite.config.ts(у Laravel-проєктах@часто вже налаштовано плагіном чи шаблоном стартового набору):
import { fileURLToPath, URL } from 'node:url';
export default defineConfig({
resolve: {
alias: { '@': fileURLToPath(new URL('./resources/js', import.meta.url)) },
},
});
- Vitest - бере
resolve.aliasз конфігурації Vite; - Node.js з вбудованим запуском TypeScript - не читає
tsconfig.jsonіpathsне підтримує. Альтернатива - subpath imports уpackage.json("imports": { "#/*": "./src/*" }), які розуміють і Node.js, і TypeScript.
Типові помилки:
- псевдонім є в
tsconfig.json, але не у збирачі - редактор задоволений, а збірка падає з «Failed to resolve import»; - різні значення в двох місцях - редактор показує один файл, а в зібраному коді опиняється інший;
pathsу бібліотеці, яку публікують на npm, - у споживачів ці шляхи не працюватимуть; у пакетах кращеimports/exportsзpackage.json.
Глобальні змінні середовища - process, Buffer, describe, it, expect - TypeScript знає не сам, а з пакетів типів: @types/node, @types/jest тощо. Опція types визначає, які з таких пакетів підключати глобально, без явного імпорту.
Що змінилося. До TypeScript 5.9 включно значення за замовчуванням було «усі пакети з node_modules/@types». У великих проєктах це сотні пакетів, підтягнутих транзитивно, - повільна перевірка й випадкові глобальні типи.
З TypeScript 6.0 (і в 7.0) types за замовчуванням - порожній список []. Після оновлення проєкт, що покладався на автоматичне підключення, бачить:
error TS2591: Cannot find name 'process'. Do you need to install type definitions for node?
Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.
Рішення - перелічити потрібні пакети явно:
{
"compilerOptions": {
"types": ["node", "vite/client"]
}
}
node- для коду, що працює в Node.js (конфіги, скрипти, SSR);vite/client- типиimport.meta.env,import.meta.hotі імпорту ресурсів (.svg,.css) у Vite-застосунку;vitest/globals- якщо тести використовують глобальніdescribe/it.
Повернути стару поведінку можна значенням ["*"], але документація TypeScript радить явний список: за їхніми даними, багато проєктів пришвидшили збірку на 20-50% лише завдяки цьому.
Що варто знати:
typesстосується лише глобальних оголошень. Пакети, які ви імпортуєте (import express from 'express'), підключаються через імпорт і не потребують запису вtypes;- різні частини проєкту - різні глобальні типи: код браузера не повинен бачити
process, а конфіги Vite -document. Тому шаблони Vite мають два конфіги (tsconfig.app.jsonіtsconfig.node.json) з різнимиtypesіlib; - пакет має бути встановлений: запис у
typesбез@types/nodeуdevDependenciesдасть помилку «Cannot find type definition file».