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

Як працюють ES-модулі в TypeScript і чому в імпортах інколи пишуть .js, хоча файл .ts?

TypeScript використовує синтаксис ES-модулів: файл з import чи export на верхньому рівні - модуль зі своєю областю видимості.

// money.ts
export function formatPrice(amount: number): string {
  return `${amount.toFixed(2)} грн`;
}
export type Currency = 'UAH' | 'USD';

// app.ts
import { formatPrice, type Currency } from './money.js';

Файл без import/export - скрипт: його оголошення потрапляють у глобальну область. Тому в TypeScript-файлах інколи пишуть порожній export {} - щоб файл став модулем.

Чому .js в імпорті .ts-файлу. TypeScript не переписує шляхи імпортів при компіляції: що написано в коді, те й опиниться в зібраному JavaScript. Після компіляції money.ts стане money.js, і Node.js шукатиме саме ./money.js. Тому з moduleResolution: "nodenext" відносні імпорти пишуть з розширенням виконуваного файлу - .js, а TypeScript розуміє, що йдеться про money.ts.

Що залежить від налаштувань:

  • moduleResolution: "bundler" (Vite, webpack, esbuild) - розширення можна не писати: збирач сам знайде файл. Найзручніше для фронтенду;
  • moduleResolution: "nodenext" - правила Node.js: розширення обов'язкове для ES-модулів, а тип модуля (ESM чи CommonJS) визначається полем "type" у package.json або розширенням .mts/.cts;
  • запуск .ts напряму (стирання типів у Node.js, Bun, Deno) - можна імпортувати з .ts за allowImportingTsExtensions; для бібліотек, що компілюються, rewriteRelativeImportExtensions перепише .ts на .js у результаті.

TypeScript 6/7: старі режими moduleResolution: "node" (node10) і "classic" видалено - лишилися nodenext і bundler. Типове значення module - esnext.

Корисне правило: спосіб резолюції модулів у tsconfig має відповідати тому, хто реально виконує код - збирач, Node.js чи інший рушій. Інакше TypeScript погоджуватиметься з імпортами, які не працюють під час виконання.

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

Схожі питання