Dilshod.dev

Node.js endi TypeScript'ni o'zi ishlatadi. Build bosqichini o'chirsak bo'ladimi?

Node 24 tiplarni ishga tushirish paytida olib tashlaydi, ya'ni `node server.ts` shunchaki ishlaydi. Bu chinakam foydali — lekin bu Node TypeScript'ni qo'llab-quvvatlaydi degani emas. Chegara aslida qayerdan o'tishini ko'ramiz.

Muallif: Dilshod Abdullayev6 daqiqa o'qish

Taxminan o'n yil davomida serverda TypeScript ishlatish build bosqichini qabul qilish degani edi. Siz .ts yozardingiz, biror narsa uni .js ga aylantirardi, siz esa natijani ishga tushirardingiz. Qaysi "biror narsa" degan savolda hammaning fikri bor edi — tsc, ts-node, esbuild, tsx, swc — lekin "umuman kerakmi" degan savolda hech kim bahslashmasdi.

Node 24 standartni o'zgartirdi. node server.ts deb ishga tushirasiz va u ishlaydi: bayroq yo'q, loader yo'q, dist/ papkasi yo'q. Bu haqiqiy yaxshilanish va men uni har kuni ishlataman. Shu bilan birga u muntazam ravishda ortiqcha maqtaladi — sarlavhani o'qib, mexanizmni o'tkazib yuborgan odamni bu keyin tishlaydi.

Demak: aslida nima sodir bo'lyapti va bu production servisi uchun nimani anglatadi.

Kompilyatsiya emas, tiplarni o'chirish

Node TypeScript'ni kompilyatsiya qilmaydi. U tiplarni o'chiradi.

Ichkarida Node amaro modulidan foydalanadi, u esa SWC'ni o'raydi. .ts faylni yuklaganda u har bir tip annotatsiyasi, interfeys va faqat tipga oid konstruksiyani topadi va o'sha belgilarni bo'sh joy bilan almashtiradi. Hech nima bilan emas — probellar bilan. Keyin natijani JavaScript sifatida ishga tushiradi.

O'sha probel tafsiloti — eng chiroyli joyi. O'chirilgan kod originaldagi bayt pozitsiyalarini egallab turgani uchun qator va ustun raqamlari o'zgarmaydi. Stack trace source map'siz ham sizning .ts faylingizdagi to'g'ri qatorni ko'rsatadi. Bu qadar kech qo'shilgan runtime imkoniyati uchun chindan ham toza dizayn.

// siz yozgan narsa
interface Payment {
  id: string;
  amountTiyin: number;
}
 
export function isSettled(p: Payment): boolean {
  return p.amountTiyin > 0;
}
// Node bajaradigan narsa (probellar saqlanadi, bu yerda siqib ko'rsatilgan)
export function isSettled(p) {
  return p.amountTiyin > 0;
}

interface yo'qoldi. : Payment va : boolean yo'qoldi. Bu jarayonda hech narsa tekshirilmadi — va keyingi bo'limning butun mazmuni shu.

Node hech narsani tekshirmaydi

Odamlar o'tkazib yuboradigan qism shu, va u bu postdagi qolgan hamma narsadan muhimroq.

Tiplarni o'chirish tiplarni olib tashlaydi. Ularni tasdiqlamaydi. node server.ts tsc qirq xato bilan rad etadigan faylni bemalol ishlatib yuboradi. Agar number ga string biriktirsangiz, Node'ga farqi yo'q; u kodga qaramasidan oldinroq shu haqda aytadigan annotatsiyani o'chirib tashlagan.

Ya'ni: native TypeScript qo'llab-quvvatlashi build bosqichini olib tashlaydi, tip tekshiruvchini emas. Sizga CI'da tsc --noEmit baribir kerak. Agar build skriptingizni o'chirish bilan birga tiplar tekshiriladigan yagona joyni ham o'chirsangiz, siz quvuringizni soddalashtirmadingiz — TypeScript'ni jimgina hujjatga aylantirdingiz.

Men buni package.json da oshkora saqlayman:

{
  "scripts": {
    "dev": "node --watch src/main.ts",
    "start": "node src/main.ts",
    "typecheck": "tsc --noEmit"
  }
}

typecheck CI'da va pre-push hook'da ishlaydi. Runtime soddalashdi; kafolat esa joyidan qimirlamadi.

Nima o'chirishdan omon qolmaydi

O'chirish faqat runtime xatti-harakatini o'zgartirmasdan olib tashlash mumkin bo'lgan sintaksis ustida ishlaydi. TypeScript'ning bir nechta imkoniyati bu sinovdan o'tmaydi, chunki ular kod chiqaradi:

  • enum — runtime'da haqiqiy obyekt mavjud, demak o'chiradigan narsa yo'q.
  • Parametr xossalariconstructor(private repo: Repo) {} yashirin ravishda this.repo ga qiymat beradi. Bu biriktirish — xatti-harakat.
  • Runtime qiymatlari bo'lgan namespace'lar.
  • Dekoratorlar — ular klass aniqlanish paytida funksiyalarni chaqiradi.

Oxirgisi ko'p backend kod uchun hal qiluvchi. Agar servisingiz NestJS bo'lsa, dekoratorlar uslub tanlovi emas, ular freymvorkning o'zi: @Injectable(), @Controller(), @Get(). Tiplarni o'chirish uni ishlatib yubora olmaydi.

Va bu yerdagi farq ko'ringanidan keskinroq. --experimental-transform-types ro'yxatdagi birinchi uchtasini hal qiladi — u enum, namespace va parametr xossalarini shunchaki o'chirmasdan, o'zgartiradi. Dekoratorlarni esa hal qilmaydi. Dekoratorlar hali TC39 uchinchi bosqich taklifi, shuning uchun Node ularni o'qiydi va o'zgartirish o'rniga xato beradi; ularni yoqadigan bayroq yo'q. Dekoratorlarga asoslangan freymvork uchun sizga haqiqiy kompilyator kerak — tsc, SWC, esbuild — yoki freymvorkning o'z build'i. Yangiroq Node emas.

Bu NestJS'ga ham, Node'ga ham tanqid emas. Bu — chegara, va u qayerda turganini bilish bir kunlik vaqtni tejaydi.

Amaliy almashtirishlar mexanik:

// buning o'rniga: enum PaymentStatus { Pending = 'pending', Settled = 'settled' }
const PaymentStatus = {
  Pending: 'pending',
  Settled: 'settled',
} as const;
 
type PaymentStatus = (typeof PaymentStatus)[keyof typeof PaymentStatus];

Rostini aytsam, men bu variantni runtime savolidan qat'i nazar afzal ko'raman — u TypeScript'ga xos emit semantikasi bo'lmagan oddiy obyekt beradi, union tip esa ikki marta e'lon qilinmasdan hosil qilinadi.

Import kengaytmasi tuzog'i

Odamlarni ilintiradigan ikkinchi narsa: ESM'da siz aslida yuklanayotgan faylni import qilasiz.

import { isSettled } from './payments.ts';   // native ishga tushirishda to'g'ri
import { isSettled } from './payments.js';   // tsc JS chiqarganda to'g'ri

Ikkalasi ham qonuniy; ular boshqa-boshqa dunyolarni tasvirlaydi. .ts ni to'g'ridan-to'g'ri ishlatsangiz, ./payments.js mavjud emas. Avval kompilyatsiya qilsangiz, chiqishda ./payments.ts yo'q. Ikki konvensiyani bitta kod bazasida aralashtirish — xato yozilgan nomga o'xshab o'qiladigan modul topilmadi xatosini keltirib chiqarishning ishonchli usuli.

Har loyihada bittasini tanlang va tsconfig.json ni shunga moslang — native yo'lni tanlasangiz, allowImportingTsExtensions va rewriteRelativeImportExtensions.

Men buni qayerda haqiqatan qabul qildim

Backend ishi uchun halol bo'linishim:

Ha, darhol: skriptlar, migratsiyalar, seeder'lar, bir martalik operatsion vositalar, kichik servislar. Kod hajmiga nisbatan build bosqichi sof ortiqcha yuk bo'lgan hamma joyda. Texnik xizmat skriptining bog'liqliklar ro'yxatidan tsx ni o'chirish — kichik, ammo haqiqiy yutuq, va bunday fayllarda dekoratorlar kamdan-kam ishlatiladi.

Hali emas: asosiy NestJS servisi. Dekoratorlar buni bugun istisno qiladi, va istisno qilmaganda ham build allaqachon boshqa ishlarni bajaryapti — bundling, asset ko'chirish, environment kiritish. Hali to'rt bosqichi bor quvurdan bitta bosqichni olib tashlash — soddalashtirish emas, nomini o'zgartirish.

Men ishlatadigan umumiy qoida: native ishga tushirish siz ishlatadigan kod uchun ajoyib standart, va siz artefakt sifatida yetkazadigan kod uchun yomon standart. Development, skriptlar, vositalar — manbani ishlating. Takrorlanadigan, minimal, tekshiriladigan chiqish kerak bo'lgan production konteynerlar — baribir build qiling.

Shubha bilan qarashga arziydigan qism

Siz ko'radigan ifoda — "build bosqichlarining oxiri". Men bunga ishonmayman, va sababini aytishga arziydi deb o'ylayman.

Build bosqichlari kamdan-kam faqat TypeScript'ni o'girish uchun mavjud bo'ladi. Ular mavjud, chunki kimgadir o'lik kodni yo'q qilish, yoki ingichka konteyner uchun bitta faylga bundling, yoki versiya satrini ichkariga joylash, yoki faqat development uchun mo'ljallangan shoxlarni kesish kerak edi. Tiplarni o'girish bir nechta vazifadan biri edi — ko'pincha eng qiziqmasi. Uni olib tashlash build'ni emas, build'ga bo'lgan sabablardan bittasini olib tashlaydi.

Chindan o'zgargan narsa — kirish bo'sag'asi. TypeScript loyihasini boshlash endi birinchi kuniyoq toolchain qarorini talab qilmaydi. node index.ts ishlaydi. O'rganayotgan odam uchun yoki 200 qatordan oshmaydigan skript uchun bu marosimchilikning sezilarli kamayishi — marosimchilikni kamaytirish esa yetarlicha qadrlanmaydi.

Faqat tsc --noEmit ni ko'z oldingizda saqlang.

Manbalar: Node.js 24 relizi eslatmalari; tiplarni o'chirish va amaro moduli bo'yicha Node.js hujjati.

O'xshash maqolalar

backendnodejs

Qulashdan omon chiqadigan background job'lar

Deploy worker'larni ish o'rtasida qayta ishga tushirdi va xatlar shunchaki yo'q bo'ldi. O'lgan jarayon ma'lumot yo'qotish emas, shunchaki kechikish bo'ladigan queue qanday quriladi.

11 daqiqa o'qish
backendpayments

Soya rejimi: kodni ishonishdan oldin isbotlash

Joytop'dagi yangi to'lov tasdiqlash kodi bir hafta productionda soya rejimida ishladi — qaror qabul qilmasdan, faqat kuzatib. Ertaga u yagona qaror qiluvchiga aylanadi. Soya rejimi nima, u nimadan himoya qiladi va nega uni kuzatuvsiz yoqib qo'yib bo'lmaydi.

3 daqiqa o'qish
system-designbackend

Ikki marta yechilgan to'lov

Qayta urinish takroriy so'rov emas — to'lov ikki marta o'tib ketguncha. Idempotentlik kalitlari aslida qanday ishlaydi, sodda variant nega baribir ikki marta yechadi va qaysi Postgres cheklovi kafolatni haqiqiy qiladi.

7 daqiqa o'qish