Vite, esbuild, oxc, swc і Node.js перетворюють TypeScript на JavaScript по одному файлу і без перевірки типів - просто прибирають анотації. Це швидко, але такий інструмент не бачить інших файлів проєкту. Частина конструкцій TypeScript без знання інших файлів перетворюється неправильно.
Головна проблема - імпорт типу:
// types.ts
export type User = { id: number };
// app.ts
import { User } from './types';
Компілятор TypeScript знає, що User - тип, і прибере імпорт. Інструмент, що бачить лише app.ts, цього не знає: залишить import { User } from './types' - і в браузері помилка «The requested module does not provide an export named 'User'».
isolatedModules - TypeScript попереджає про код, який неможливо безпечно перетворити по одному файлу: реекспорт типу без type, const enum між файлами, файли без імпортів і експортів.
verbatimModuleSyntax - строгіший і простіший підхід: імпорти лишаються в JavaScript рівно так, як написані, крім позначених type. Тому тип треба явно позначити:
import type { User } from './types';
import { fetchUser, type UserFilter } from './api';
З опцією TypeScript видасть помилку на import { User }, якщо User - лише тип.
Що обрати: у сучасних проєктах - verbatimModuleSyntax: true. Він робить поведінку однаковою для tsc, збирачів і Node.js і замінює старіші importsNotUsedAsValues і preserveValueImports. Шаблони Vite вмикають його за замовчуванням.
Наслідки, які варто знати:
- імпорти з побічними ефектами зберігаються:
import './styles.css'нікуди не зникне; import typeне виконує модуль - якщо вам потрібен побічний ефект модуля, потрібен звичайний імпорт;- з CommonJS опція змушує писати
import x = require('...')для CommonJS-виводу - у кодовій базі на ES-модулях це не відчувається; - лінтер (
@typescript-eslint/consistent-type-imports) автоматично виправляє імпорти, тож перехід на велику кодову базу - один прогін автовиправлення.
Зв'язок з Node.js: вбудоване виконання TypeScript у Node.js теж прибирає лише імпорти з type - без verbatimModuleSyntax такі помилки виявляться лише під час запуску.