IlmHamroh
JavaScript Full-stack/15-qism. TypeScript35/47-dars17 daqiqa
Mundarija (32)

TypeScript modullari: import type, verbatimModuleSyntax va .ts kengaytmali importlar

Qisqacha: TypeScript turlari JavaScript'ga o'tmaydi — shuning uchun faqat tur bo'lgan importni import type deb belgilash kerak. Aks holda turlarni o'chiradigan vositalar (Node, esbuild) uni oddiy import deb qoldiradi va ishlash paytida does not provide an export named xatosi chiqadi. verbatimModuleSyntax buni kompilyatsiyada ushlaydi. Node .ts ni o'zi ishga tushirganda importda "./menu.ts" yoziladi, build paytida esa rewriteRelativeImportExtensions uni "./menu.js" ga almashtiradi.

Bu darsda

  • import type, import { type X } va export type ni ishlatasiz va ular .js da nima qoldirishini bilasiz.
  • verbatimModuleSyntax va isolatedModules nima uchun kerakligini — "har fayl alohida" tamoyilini — tushuntirasiz.
  • .ts kengaytmali importlar va rewriteRelativeImportExtensions bilan build'ni sozlaysiz.
  • paths taxalluslari nega Node'da ishlamasligini va o'rniga package.json dagi imports ni ishlatasiz.
  • .mts/.cts va CommonJS bilan TypeScript qanday ishlashini bilasiz.

Oldin bilishingiz kerak: Strict bayroqlar oilasi, tsconfig.json chuqur, ESM import, CommonJS va ESM.

1. Nega bu kerak?

O'tgan darsda qat'iy bayroqlarni ko'rdik. Endi modullar — fayllar orasidagi aloqa. TypeScript'da bitta yangi muammo bor: importning ba'zilari qiymat (funksiya, massiv), ba'zilari esa faqat tur. Turlar ishlash paytida yo'q. Bu oddiy faktdan butun bir dars kelib chiqadi.

«Bahor» loyihasida Sardor turlarni alohida faylga chiqardi:

ts
// types.ts
export type MenuItem = { name: string; price: number };
ts
// main.ts
import { MenuItem } from "./types.ts";
const osh: MenuItem = { name: "Osh", price: 35000 };
console.log(osh.name);

npx tsc — xatosiz (sozlamada verbatimModuleSyntax yo'q). Sardor node main.ts ni ishga tushirdi (TypeScript'ni o'rnatish darsidagi Node type stripping). Natija:

text
import { MenuItem } from "./types.ts";
         ^^^^^^^^
SyntaxError: The requested module './types.ts' does not provide an export named 'MenuItem'

"So'ralgan ./types.ts moduli MenuItem degan eksportni bermaydi". Nima bo'ldi? Node .ts fayldan turlarni o'chiradi. types.ts dagi export type MenuItem — butunlay o'chdi, fayl bo'sh qoldi. main.ts dagi import { MenuItem } esa oddiy import ko'rinishida — Node bilmaydi, MenuItem tur yoki qiymat. U importni qoldirdi va bo'sh moduldan MenuItem ni so'radi.

tsc buni bilardi — u ikkala faylni ham ko'radi. Node esa (va esbuild, SWC kabi tezkor vositalar ham) har faylni alohida o'qiydi va qo'shni faylga qaramaydi. Yechim — importning o'zida "bu faqat tur" deb yozish.

2. import type va export type

2.1 Uch yozuv

ts
import type { MenuItem } from "./types.ts";          // 1
import { type MenuItem, MENU } from "./menu.ts";     // 2
export type { MenuItem } from "./types.ts";          // 3
Yozuv Ma'nosi .js da nima qoladi
import type { X } butun import — faqat turlar hech narsa — qator o'chadi
import { type X, y } X — tur, y — qiymat import { y }
export type { X } tur sifatida qayta eksport hech narsa

Sardorning tuzatilgan kodi:

ts
// main.ts
import type { MenuItem } from "./types.ts";
const osh: MenuItem = { name: "Osh", price: 35000 };
console.log(osh.name);

Endi Node ham, tsc ham import type qatorini butunlay o'chiradi — types.ts umuman yuklanmaydi.

2.2 import type va import { type … } farqi

Mayda, lekin muhim farq. tsc (verbatimModuleSyntax bilan) ikki xil importni shunday chiqardi:

ts
import type { MenuItem } from "./lib/menu.ts";
import { type MenuItem as Item } from "./lib/menu.ts";
js
import {} from "./lib/menu.js";

Birinchi qator butunlay yo'qoldi. Ikkinchisidan import {} from "./lib/menu.js" qoldi: { } ichi bo'sh, lekin modul baribir yuklanadi va undagi kod bajariladi. Qoida: hamma import qilinadiganlar tur bo'lsa — import type; aralash bo'lsa — import { type X, y }.

Tekshirib ko'ring: menu.ts da console.log("menyu yuklandi") qatori bor. import { type MenuItem } from "./menu.ts" yozilgan faylni ishga tushirsangiz, bu yozuv chiqadimi? import type { MenuItem } bilan-chi?

Javob

Birinchisida — chiqadi: import {} from "./menu.js" modulni yuklaydi va uning kodi bajariladi. Ikkinchisida — chiqmaydi: qator butunlay o'chadi. Ko'pincha farqi yo'q, lekin modul "yon ta'sirli" bo'lsa (yuklanganda nimadir qiladi) — muhim.

3. verbatimModuleSyntax va isolatedModules

3.1 verbatimModuleSyntax — "yozilganini aynan qoldir"

verbatimModuleSyntax ("so'zma-so'z modul sintaksisi") — qoida: type deb belgilanmagan har bir import va eksport .js da aynan qoladi. Shuning uchun tsc tur bo'lgan, lekin type siz importni xato deb ko'rsatadi:

ts
// @ts-options: {"verbatimModuleSyntax": true}
import { PathLike, existsSync } from "node:fs";
const file: PathLike = "menu.json";
console.log(existsSync(file));

Kompilyator:

text
TS1484: 'PathLike' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.

Tarjimasi: "PathLike — tur, verbatimModuleSyntax yoqilganda uni faqat-tur importi bilan olish kerak". PathLike — Node turlaridagi "fayl yo'li" turi (@types/node dan); existsSync — haqiqiy funksiya. Tuzatilgani:

ts
// @ts-options: {"verbatimModuleSyntax": true}
import { type PathLike, existsSync } from "node:fs";
const file: PathLike = "menu-yoq.json";
console.log(existsSync(file)); // false

Qayta eksportda ham xuddi shunday — TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. («Ko'p uchraydigan xatolar» va mashqda haqiqiy chiqishi bor).

verbatimModuleSyntax siz TypeScript importni o'zi "tozalardi": turga ishlatilgan importni jim o'chirib yuborardi. Bu tsc uchun ishlaydi, lekin Node va bundler'lar buni qila olmaydi — ular faylni yolg'iz ko'radi. Bayroq hamma vositalar bir xil natija berishini kafolatlaydi. tsc --init (TypeScript 7.0.2) uni yoqib qo'yadi; mashqlar papkamizda va vazifalar da ham yoqiq.

3.2 isolatedModules — yengilroq qarindoshi

isolatedModules — "har fayl alohida tarjima qilinishi mumkin bo'lsin". U faqat yolg'iz faylda hal qilib bo'lmaydigan holatlarni taqiqlaydi: masalan, turni type siz qayta eksport qilish (TS1205 — xuddi shu xabar, faqat 'isolatedModules' is enabled). import { MenuItem } ni esa o'tkazadi — chunki tsc uni o'zi o'chira oladi.

isolatedModules verbatimModuleSyntax
export { MenuItem } from … (tur) TS1205 TS1205
import { MenuItem } (tur) o'tadi TS1484
Natija bundler'lar bilan xavfsiz hamma vosita bilan aynan bir xil

verbatimModuleSyntax — qat'iyroq va soddaroq qoida ("yozilgani qoladi"), isolatedModules ning hamma tekshiruvlarini o'z ichiga oladi. Yangi loyihalarda shu tanlanadi.

3.3 erasableSyntaxOnly — faqat o'chirib bo'ladigan sintaksis

Node turlarni o'chiradi, lekin TypeScript'ning ba'zi yozuvlarini JavaScript'ga o'girish kerak — ularni o'chirib bo'lmaydi: enum, qiymatli namespace, klass parametr xususiyatlari (enum va muqobillari, Klasslar) va eski CommonJS importi:

ts
// @ts-options: {"erasableSyntaxOnly": true}
import fs = require("node:fs");

Kompilyator:

text
TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.

"erasableSyntaxOnly yoqilganda bu sintaksisga ruxsat yo'q". import x = require(…) — TypeScript'ning o'z yozuvi, uni o'chirib emas, const x = require(…) ga aylantirib bo'ladi. Bayroq Node to'g'ridan-to'g'ri ishga tushira oladigan kodni kafolatlaydi.

3.4 Nega JavaScript'da bu muammo yo'q edi?

JavaScript'da har bir eksport — qiymat: funksiya, massiv, son. Import qilingan nom ishlash paytida doim mavjud. TypeScript esa ikkinchi "qavat" qo'shdi — faqat kompilyatsiyada yashaydigan nomlar. Bir fayl ichida bu muammo emas: tur va qiymat yonma-yon, tsc ularni ajrata oladi. Muammo fayllar chegarasida paydo bo'ladi: import qatoriga qarab, nom qaysi qavatdan ekanini bilib bo'lmaydi.

import type — shu chegarani ko'rinadigan qiladi. Kod o'quvchisi ham qatorga qarab biladi: "bu fayldan faqat turlar olinyapti, ishlash paytida u yuklanmaydi". Bu modullar orasidagi bog'liqlikni tushunishni ham osonlashtiradi: import type — "yumshoq" bog'liqlik, oddiy import — "qattiq" (fayl yuklanadi, kodi bajariladi).

3.5 Skript yoki modul: export {}

Tur annotatsiyasi darsida tsc chiqishining oxirida export {}; qatorini ko'rgan edik. U nima? TypeScript har faylni ikki xildan biri deb biladi:

  • modul — faylda import yoki export bor: undagi nomlar faqat shu faylniki;
  • skript — ikkalasi ham yo'q: undagi nomlar global, boshqa fayllar bilan bitta maydonda.

Ikki skript faylda bir xil nom bo'lsa, ular to'qnashadi. a.ts va b.ts — ikkalasida const total = …, import/export yo'q. Sozlamasiz npx tsc --ignoreConfig --noEmit a.ts b.ts:

text
a.ts(1,7): error TS2451: Cannot redeclare block-scoped variable 'total'.
b.ts(1,7): error TS2451: Cannot redeclare block-scoped variable 'total'.

TypeScript aytyapti: "total blok o'zgaruvchisini qayta e'lon qilib bo'lmaydi" — ikki fayl bitta global maydonni bo'lishyapti. Yechim — faylni modul qilish. tsc --init yozgan "moduleDetection": "force" aynan shuni qiladi: har fayl — modul, import bo'lmasa ham. Shunda tsc chiqishga export {}; qo'shadi — "bu fayl modul" degan belgi, JavaScript'da ham fayl modul bo'lib qolsin. Skript kerak bo'lgan kam holatlar ham bor: global turlarni e'lon qiladigan .d.ts (keyingi dars) va <script> bilan ulanadigan oddiy skript (vazifalar dagi tema.js).

3.6 Dinamik import() va uning turi

Dinamik import() — modulni kerak bo'lganda yuklash. Uning turini yozish uchun maxsus yozuv bor — typeof import("…"):

ts
// 35-modullar/lazy.ts — menyu moduli faqat kerak bo'lganda
type MenuModule = typeof import("./menu.ts");

export async function loadPrice(dish: string): Promise<number> {
  const menu: MenuModule = await import("./menu.ts");
  return menu.priceOf(dish);
}

typeof import("./menu.ts") — "shu modul eksportlarining turi": { MENU: …; priceOf: (dish: string) => number }. Bu qator ham faqat tur — menu.ts ni oldindan yuklamaydi. Biz sinadik: npx tsc — toza, await loadPrice("Osh") — 35000. vazifalar da ham shunday: asosiy.ts o'lchov modulini import("./olchov.ts") bilan, sahifa yuklangandan keyin oladi.

4. .ts kengaytmali importlar

4.1 Ikki dunyo

tsconfig.json chuqur darsining mashqida bitta loyihada ikki xil import bor edi: test "./shifts.ts" ni, main.ts esa "./shifts.js" ni import qilardi. Sababi:

Kim ishga tushiradi Diskdagi fayl Importda
Node, .ts dan to'g'ridan-to'g'ri shifts.ts "./shifts.ts"
Node, build natijasidan (dist/) shifts.js "./shifts.js"

tsc importdagi yo'lni standart holatda o'zgartirmaydi. Shuning uchun avval TypeScript'da .js deb yozish odat edi ("kelajakdagi faylga ishora"): manbada .js fayl yo'q, lekin build'dan keyin paydo bo'ladi, tsc esa "./menu.js" ni ko'rib, yonidagi menu.ts ni topadi. Node type stripping bilan esa .ts dan ishga tushirganda .js fayl umuman yo'q — "./menu.js" importi ERR_MODULE_NOT_FOUND beradi. Node faylni "taxmin qilmaydi": importda qaysi nom yozilgan bo'lsa, diskdan aynan shuni qidiradi.

4.2 Ikki bayroq

  • allowImportingTsExtensions — "./menu.ts" yozishga ruxsat. Lekin faqat .js yozilmaganda: noEmit (mashqlar papkamiz) yoki emitDeclarationOnly bilan. Usiz — o'rnatish darsidagi TS5097.
  • rewriteRelativeImportExtensions (TypeScript 5.7 dan) — "./menu.ts" deb yozing, tsc build paytida "./menu.js" ga almashtiradi.

Build qiladigan loyihada allowImportingTsExtensions ni yoqib ko'rdik:

text
tsconfig.json(7,35): error TS5096: Option 'allowImportingTsExtensions' can only be used when one of 'noEmit', 'emitDeclarationOnly', or 'rewriteRelativeImportExtensions' is set.

"allowImportingTsExtensions faqat noEmit, emitDeclarationOnly yoki rewriteRelativeImportExtensions bilan ishlatiladi". Build bo'lsa — ikkinchi bayroq kerak. rewriteRelativeImportExtensions bilan manba:

ts
// src/main.ts
import type { MenuItem } from "./lib/menu.ts";
import { MENU } from "./lib/menu.ts";
const first: MenuItem | undefined = MENU[0];
console.log(first?.name);

tsc natijasi (dist/main.js):

js
import { MENU } from "./lib/menu.js";
const first = MENU[0];
console.log(first?.name);

Ikki narsa bo'ldi: import type qatori o'chdi, .ts — .js ga almashdi. node src/main.ts ham, node dist/main.js ham Osh chiqardi. Bitta yo'l — ikki muhit.

flowchart LR
  A["src/main.ts: import ./menu.ts"] --> B["node src/main.ts"]
  A --> C["tsc + rewriteRelativeImportExtensions"]
  C --> D["dist/main.js: import ./menu.js"]
  D --> E["node dist/main.js"]
  B --> F["Osh"]
  E --> F

vazifalar aynan shunday: testlar Node'da .ts dan ishlaydi, brauzer dist/ dagi .js ni oladi, importlar — "./sinxron.ts" (Discriminated union qadamidan beri).

Tekshirib ko'ring: rewriteRelativeImportExtensions import { x } from "lodash.ts" ni ham o'zgartiradimi?

Javob

Yo'q. Bayroq nomida "relative" bor — faqat nisbiy yo'llar (./, ../ bilan boshlanadigan) almashtiriladi. Paket nomlari ("lodash", "node:fs") o'zgarmaydi — ular .ts fayl emas.

5. paths taxalluslari va TypeScript ushlamaydigan tuzoq

5.1 paths — faqat tekshiruv uchun

Katta loyihada "../../../lib/menu.ts" kabi uzun yo'llar paydo bo'ladi. paths — qisqa taxallus:

json
{
  "compilerOptions": {
    "paths": { "@/*": ["./src/*"] }
  }
}

Endi import { MENU } from "@/lib/menu.js" — tsc uni src/lib/menu.ts ga topadi va tekshiradi. Lekin build natijasi:

js
import { MENU } from "@/lib/menu.js";
console.log(MENU.length);

tsc yo'lni o'zgartirmadi — paths faqat tur tekshiruvi uchun. Node esa:

text
Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@/lib' imported from …\dist\main.js

"@/lib paketi topilmadi". Node @/ ni npm paketi deb o'yladi. Bu — darsning "TypeScript ushlamaydigan" tuzog'i: tsc toza, dastur esa ishga tushmaydi. Vite kabi bundler'lar paths ni o'zlari tushunadi (16-qism), Node esa — yo'q.

5.2 Node uchun: package.json dagi imports

Node'ning o'z taxallus mexanizmi bor — package.json dagi imports maydoni. Nomlar # bilan boshlanadi:

json
{
  "type": "module",
  "imports": { "#lib/*": "./src/lib/*" }
}
ts
// src/main.ts
import { MENU } from "#lib/menu.ts";
console.log(MENU.length);

module: nodenext dagi tsc ham, Node ham imports ni biladi: npx tsc — toza, node src/main.ts — 1. Bitta taxallus, ikki vosita bir xil tushunadi. paths dan farqi — u standart, Node'ning o'zida.

6. ESM va CommonJS: .mts va .cts

CommonJS va ESM darsidan bilasiz: Node'da ikki modul tizimi bor. module: nodenext da TypeScript fayl turini Node kabi aniqlaydi:

Fayl Modul tizimi Build natijasi
.ts package.json dagi "type" ga qarab .js
.mts doim ESM .mjs
.cts doim CommonJS .cjs

O'tgan darsda ko'rdik: bir xil .ts "type": "module" bilan ESM, usiz — CommonJS (require, exports) bo'lib chiqdi. ESM loyihada bitta CommonJS fayl kerak bo'lsa (masalan, eski vosita sozlamasi) — uni .cts deb nomlang. Ichida const fs = require("node:fs") va module.exports — oddiy CommonJS. TypeScript'ning eski import fs = require() va export = yozuvlari esa erasableSyntaxOnly bilan taqiqlangan — ularni yangi kodda yozmang.

7. Ko'p uchraydigan xatolar

7.1 Turni oddiy import qilish

SyntaxError: The requested module './types.ts' does not provide an export named 'MenuItem' (Node) yoki TS1484 (verbatimModuleSyntax bilan). Tuzatish: import type { MenuItem }.

7.2 Turni type siz qayta eksport

TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. Tuzatish: export type { MenuItem } from "./types.ts".

7.3 Build'da .ts import

TS5097 yoki TS5096. Tuzatish: rewriteRelativeImportExtensions (build) yoki noEmit + allowImportingTsExtensions (faqat tekshiruv).

7.4 paths ga Node'da ishonish

ERR_MODULE_NOT_FOUND: Cannot find package '@/lib'. Tuzatish: package.json imports (#lib/*) yoki bundler.

7.5 import x = require()

TS1294 (erasableSyntaxOnly). Tuzatish: ESM'da — import fs from "node:fs"; CommonJS'da (.cts) — const fs = require("node:fs").

8. Mashqlar

1-mashq (oson): Nima qoladi?

verbatimModuleSyntax yoqilgan. Har qatordan .js da nima qoladi?

  1. import type { MenuItem } from "./types.ts"; — qator qoladimi (ha/yo'q)?
  2. import { type MenuItem, MENU } from "./menu.ts"; — qaysi nom qoladi?
  3. export type { OrderLine } from "./types.ts"; — qoladimi?
Yechim

import type va export type — butunlay o'chadi. Aralash importdan faqat qiymat qoladi: import { MENU } from "./menu.js" (build'da rewriteRelativeImportExtensions bilan .js).

2-mashq (o'rta): Taxallusni tuzating

Loyiha build qilinmaydi — Node .ts ni to'g'ridan-to'g'ri ishga tushiradi. tsconfig.json da "paths": { "@lib/*": ["./src/lib/*"] } bor va import { MENU } from "@lib/menu.ts" yozilgan. tsc toza, node src/main.ts esa ERR_MODULE_NOT_FOUND. Nima o'zgartirasiz?

Yechim

paths ni olib tashlab, package.json ga imports qo'shamiz va taxallusni # bilan boshlaymiz:

json
{
  "type": "module",
  "imports": { "#lib/*": "./src/lib/*" }
}

Importda: import { MENU } from "#lib/menu.ts". tsconfig.json da module: nodenext (u imports ni o'qiydi) va allowImportingTsExtensions + noEmit. Biz shu sozlamani sinadik: npx tsc — toza, node src/main.ts — 1. # majburiy — Node imports nomlarini shu belgidan taniydi va ularni npm paketlari bilan adashtirmaydi.

3-mashq (qiyin): Amaliy tajriba — modulning "old eshigi"

kurs/mashqlar/15/35-modullar/ da (umumiy tsconfig.json — verbatimModuleSyntax va allowImportingTsExtensions yoqiq) to'rt fayl yarating:

  • types.ts — faqat turlar: MenuItem (name, price), OrderLine (dish, qty).
  • menu.ts — MENU (osh, lag'mon, ko'k choy) va priceOf(dish) (yo'q taom — RangeError).
  • order.ts — orderTotal(lines).
  • index.ts — barrel ("old eshik"): qolgan uchta fayldan kerakli hamma narsani qayta eksport qiladi. Boshqa kod faqat ./index.ts dan import qiladi.

Avval order.ts da import { OrderLine } va index.ts da export { MenuItem, OrderLine } from "./types.ts" deb (type siz) yozing. npx tsc --pretty false ni, keyin node --test 35-modullar/index.test.ts ni ishga tushiring.

Yechim

type siz variantda tsc uchta xato berdi:

text
35-modullar/index.ts(4,10): error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'.
35-modullar/index.ts(4,20): error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'.
35-modullar/order.ts(2,10): error TS1484: 'OrderLine' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.

Node esa tsc ni kutmaydi — testni baribir ishga tushiradi va yiqiladi:

text
SyntaxError: The requested module './types.ts' does not provide an export named 'OrderLine'
✖ 35-modullar\index.test.ts (228.7554ms)

«Nega bu kerak?» bo'limidagi xatoning o'zi. Shuning uchun ish tartibi: avval npx tsc, keyin testlar.

ts
// 35-modullar/types.ts — faqat turlar (JS'da bo'sh modul)
export type MenuItem = {
  readonly name: string;
  readonly price: number;
};
export type OrderLine = {
  readonly dish: string;
  readonly qty: number;
};
ts
// 35-modullar/menu.ts — menyu va narx
import type { MenuItem } from "./types.ts";

export const MENU: readonly MenuItem[] = [
  { name: "Osh", price: 35000 },
  { name: "Lag'mon", price: 28000 },
  { name: "Ko'k choy", price: 5000 },
];

export function priceOf(dish: string): number {
  const item = MENU.find((m) => m.name === dish);
  if (item === undefined) {
    throw new RangeError(`Menyuda yo'q: ${dish}`);
  }
  return item.price;
}
ts
// 35-modullar/order.ts — buyurtma summasi
import type { OrderLine } from "./types.ts";
import { priceOf } from "./menu.ts";

export function orderTotal(lines: readonly OrderLine[]): number {
  let sum = 0;
  for (const line of lines) {
    sum += priceOf(line.dish) * line.qty;
  }
  return sum;
}
ts
// 35-modullar/index.ts — modulning "old eshigi"
export { MENU, priceOf } from "./menu.ts";
export { orderTotal } from "./order.ts";
export type { MenuItem, OrderLine } from "./types.ts";
ts
// 35-modullar/index.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { MENU, orderTotal, priceOf } from "./index.ts";
import type { OrderLine } from "./index.ts";

test("priceOf: menyudagi narx", () => {
  assert.equal(priceOf("Lag'mon"), 28000);
  assert.throws(() => priceOf("Pizza"), RangeError);
});

test("orderTotal: 2 osh va 2 choy", () => {
  const lines: OrderLine[] = [
    { dish: "Osh", qty: 2 },
    { dish: "Ko'k choy", qty: 2 },
  ];
  assert.equal(orderTotal(lines), 80000);
  assert.equal(MENU.length, 3);
});

npx tsc --pretty false — chiqishsiz. node --test 35-modullar/index.test.ts bizda (Node 24.21.0):

text
✔ priceOf: menyudagi narx (3.8043ms)
✔ orderTotal: 2 osh va 2 choy (0.641ms)
ℹ tests 2
ℹ suites 0
ℹ pass 2
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 366.3781

Barrel foydasi: menu.ts ni ikkiga bo'lsangiz yoki types.ts ni ko'chirsangiz, faqat index.ts o'zgaradi — tashqi kod ./index.ts dan import qilishda davom etadi. Narxi: katta barrel'lar bundler'ni sekinlashtirishi mumkin (keraksiz modullar ham yuklanadi) — buni 16-qismda ko'ramiz.

XATOLAR.md ga qo'shing: TS1484, TS1205, TS1294, TS5096 va Node'ning does not provide an export named xatosi (TypeScript emas, lekin sababi — tur importi). Keyin kurs/mashqlar papkasidan:

bash
git add 15/35-modullar 15/XATOLAR.md
git commit -m "15/35: barrel modul — import type va export type"

9. Real ishda

  • import type — zamonaviy TypeScript kodining standart qismi: ESLint'da @typescript-eslint/consistent-type-imports qoidasi uni avtomatik talab qiladi, muharrir esa "Add import" da o'zi type qo'shadi.
  • Node type stripping va tezkor vositalar (esbuild, SWC, Vite — 16-qism) faylni alohida o'qiydi. Ular bilan ishlaydigan har loyihada verbatimModuleSyntax yoki kamida isolatedModules yoqiladi.
  • vazifalar — verbatimModuleSyntax, rewriteRelativeImportExtensions, erasableSyntaxOnly: testlar build'siz .ts dan, brauzer — dist/ dan.
  • Taxalluslar: frontend'da @/ (Vite/Next.js paths ni biladi), Node backend'da — package.json imports (#…).
  • Intervyu: "import type nega kerak?", "isolatedModules nima?", "paths nega Node'da ishlamaydi?" — amaliy savollar.

Xulosa

  • Turlar ishlash paytida yo'q: faqat tur importi — import type / import { type X }, qayta eksport — export type.
  • verbatimModuleSyntax — type siz import aynan qoladi, tur bo'lsa — TS1484/TS1205. Node va bundler'lar bilan natija bir xil bo'ladi.
  • erasableSyntaxOnly — faqat o'chirib bo'ladigan sintaksis (enum, import = require yo'q).
  • Node .ts dan: "./menu.ts" + allowImportingTsExtensions (noEmit); build bilan: rewriteRelativeImportExtensions uni .js ga almashtiradi.
  • paths faqat tekshiruv uchun — Node'da package.json imports (#lib/*).

Keyingi dars: Declaration fayllari (.d.ts) — kodsiz, faqat turlardan iborat fayllar: declare, declare module, declare global va tsc --declaration.

Manbalar

  • TypeScript Handbook: "Modules — Reference" (verbatimModuleSyntax, isolatedModules) — typescriptlang.org/docs/handbook/modules/reference.html
  • TSConfig: verbatimModuleSyntax, rewriteRelativeImportExtensions, allowImportingTsExtensions, erasableSyntaxOnly, paths — typescriptlang.org/tsconfig
  • TypeScript Release Notes 5.0 (verbatimModuleSyntax), 5.7 (rewriteRelativeImportExtensions), 5.8 (erasableSyntaxOnly) — typescriptlang.org/docs/handbook/release-notes/
  • Node.js hujjatlari: "Modules: Packages — Subpath imports" (imports) — nodejs.org/api/packages.html#subpath-imports
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
TypeScript modullari: import type, verbatimModuleSyntax va .ts kengaytmali importlar — IlmHamroh