- Node.js PR #53725 telah digabungkan, sehingga eksekusi file TypeScript kini didukung secara eksperimental melalui flag
--experimental-strip-types
- Fitur ini menghapus sintaks tipe dari sumber TypeScript dan mengubahnya menjadi sumber JavaScript, tetapi tidak melakukan pemeriksaan tipe selama proses konversi
- Implementasi awal tidak melakukan transformasi fitur khusus TypeScript seperti
enum dan namespaces, sehingga terbatas pada kode yang menjadi JavaScript hanya dengan menghapus tipe
@swc/wasm-typescript dipilih untuk implementasinya karena kesederhanaannya, yaitu tidak perlu menambahkan Rust atau Go ke toolchain Node.js
- Dalam diskusi, kendala utama yang dibahas mencakup aturan ekstensi file wajib di ESM, kebiasaan TypeScript di mana import
.js sebenarnya menunjuk ke file .ts, serta biaya source map dan posisi stack error
Cara kerja --experimental-strip-types
- Dengan mengaktifkan
--experimental-strip-types, Node.js dapat menjalankan file TypeScript
- Node.js akan mentranspilasi kode sumber TypeScript menjadi kode sumber JavaScript
- Selama proses transpilasi, pemeriksaan tipe tidak dilakukan, dan informasi tipe dibuang
- Contohnya sebagai berikut
const foo: string = "foo";
const foo = "foo";
Alasan hanya memilih penghapusan tipe dan batasan awal
- Inti PR ini adalah menghapus sintaks tipe dari sintaks TypeScript
- Runtime lain kadang mengubah fitur khusus TypeScript yang tidak ada di JavaScript, seperti
enum, menjadi JavaScript
- Implementasi awal PR ini tidak melakukan transformasi semacam itu
Enum tidak dapat digunakan
namespaces tidak dapat digunakan
- Fitur khusus TypeScript lainnya juga bukan target transformasi
- Panduan tersebut menyertakan rujukan ke
typescript.md dalam perubahan PR untuk detail implementasi dan batasannya
Memilih @swc/wasm-typescript sebagai alat implementasi
@swc/wasm-typescript adalah paket kecil yang terdiri dari file wasm dan file JavaScript yang mengikatnya
- Alat lain mengharuskan penambahan Rust atau Go ke toolchain Node.js
- SWC juga digunakan oleh Deno untuk tujuan yang sama, dan penulis PR menganggapnya sebagai pilihan yang sudah terbukti
- Ke depannya, fitur ini dipandang bisa diimplementasikan di lapisan native
- PR ini merujuk ke nodejs/loaders#217
Pembahasan interpretasi import dan ekstensi
- Import tanpa ekstensi seperti
import foo from "./foo" tidak didukung
- Di Node.js ESM ada aturan mandatory file extensions, sehingga tidak didukungnya import tanpa ekstensi diperlakukan sebagai perilaku yang disengaja
- Muncul pendapat bahwa dalam codebase modul TypeScript, sering kali digunakan ekstensi
.js di pernyataan import meskipun file aslinya adalah .ts
- Contoh:
import foo from './foo.js'
- Di sistem file sebenarnya tidak ada
./foo.js, dan yang ada hanya ./foo.ts
- Penulis PR menilai masalah ini bisa ditangani dalam iterasi berikutnya, dan penebakan ekstensi memerlukan pemeriksaan sistem file tambahan serta heuristik
- Jika
./foo.js tidak ada, periksa ./foo.ts
- Jika
./foo.ts tidak ada, periksa ./foo.js
- Diskusi ini dilacak di nodejs/loaders#208
Lokasi sumber, source map, dan stack error
- Dalam review, muncul pendapat bahwa posisi sumber yang akurat di stack error dibutuhkan dalam jangka pendek
- Salah satu pendekatan yang mungkin adalah tidak mengubah posisi sumber saat menghapus tipe sehingga pembuatan dan pemetaan source map bisa dihindari
- Disebutkan bahwa source map memiliki biaya dari sisi penggunaan memori dan performa, serta tidak sederhana
- Penulis PR menilai karena SWC sudah mendukung source map, flag untuk mengaktifkannya dapat ditambahkan
- Ia juga menilai bisa saja meminta SWC menyediakan opsi untuk mengganti sintaks yang dihapus dengan spasi agar stack error asli tidak berubah
Isu desain yang masih tersisa sebelum stabilisasi
- Dukungan TypeScript terbagi menjadi dua sumbu
- penghapusan sintaks tipe
- penyesuaian aturan resolusi agar menerima file
.ts
- Muncul kekhawatiran bahwa perubahan aturan resolusi bisa berbenturan dengan loader TypeScript yang sudah ada
- Penulis PR menjawab bahwa PR ini tidak memiliki override aturan resolusi, dan ekstensi file tetap diperlukan
- Melalui
allowImportingTsExtensions, bentuk import './file.ts' bisa didukung, dan pendekatan ini dinilai juga selaras dengan Deno
- Untuk menjalankan file sumber yang sama secara langsung sekaligus menghasilkan output JavaScript lewat build tool, tanggung jawab mengubah
file.ts menjadi file.js dapat dipegang oleh build tool
Penggabungan dan tindak lanjut
- PR digabungkan ke
nodejs:main pada 24 Juli 2024
- Skala perubahannya adalah 8 commit, 89 file, 2.190 baris tambahan, dan 25 baris dihapus
- Label yang disematkan mencakup
semver-minor, experimental, module, esm, dan notable-change
- Ada diskusi tentang apakah fitur ini perlu disebutkan di halaman panduan TypeScript di situs web, dan PR pembaruan terkait juga ditautkan
- Sebagai isu lanjutan, juga dibahas opsi untuk memasukkan versi TypeScript yang digunakan biner Node untuk penghapusan tipe ke dalam metadata rilis
1 komentar
Komentar Hacker News
Penghapusan tipe TypeScript tidak mungkin dilakukan tanpa sintaks TypeScript. Penghapusan tipe bukan pekerjaan pada level token, dan sintaks TypeScript terus berubah
Misalnya,
foo < bar & baz > ( x )pada TypeScript 1.5 diparse seperti(foo (x))karenabar&bazbukan ekspresi tipe yang valid, tetapi setelah operator tipe irisan ditambahkan, itu diparse sebagaifoo<(bar & baz)>(x)dan dihapus tipenya menjadifoo(x)Jika ingin terus memakai fitur TypeScript terbaru, Anda harus mengompilasinya ke JS atau terus menjaga versi Node tetap terbaru, dan bagi tim yang lebih suka bertahan di Node LTS ini bisa menjadi kompromi yang sulit diterima
Caranya adalah menaruh versi stabil di core, tetapi jika TypeScript merilis fitur baru atau perubahan yang memecahkan kompatibilitas, atau pengguna ingin memakai fitur eksperimental baru, mereka bisa melakukan upgrade terpisah lewat NPM
Dengan begitu pengguna tidak terkunci, sambil tetap memungkinkan dukungan untuk versi TypeScript tertentu selama masa hidup 3 tahun rilis Node.js: https://github.com/nodejs/loaders/issues/217
Perubahan sintaks besar terakhir mungkin adalah conditional types di 2.8, saat sintaks mirip operator ternary
ifmasuk ke posisi tipe. Jika ingin melakukan pemeriksaan tipe, model tipenya memang banyak berubah sejak 2.x, tetapi sintaksnya sebagian besar stabil, dan inovasi TypeScript juga kebanyakan ada di sisi model tipe dan inferensi tipeMasih di Stage 1 yang sangat awal, tetapi sudah ada upaya untuk menstandarkan sebagian besar sintaks tipe TypeScript untuk tujuan penghapusan tipe, bukan pemeriksaan tipe: https://github.com/tc39/proposal-type-annotations
Tim yang tidak terlalu peduli pada fitur terbaru V8 atau Node dan memilih bertahan di LTS kemungkinan juga kurang tertarik pada fitur TypeScript terbaru
Jika Node.js bisa menjalankan file TypeScript secara langsung, kompiler TypeScript bisa dipakai hanya sebagai pemeriksa tipe alih-alih untuk penghapusan tipe dan transformasi JavaScript. Ini mirip Python, di mana pemeriksa tipe memeriksa tipe lalu membiarkannya tetap ada, sementara interpreter mengabaikan type hint
Menariknya, di Python muncul beberapa pemeriksa tipe populer yang memakai sintaks type hint yang sama tetapi semantiknya berbeda. Sebaliknya, di JavaScript tampaknya TypeScript menjadi satu-satunya pemeriksa tipe populer secara de facto
Di Python, saya juga pernah mendengar ada yang menulis tipe di source tanpa memeriksanya, hanya memakainya seperti sintaks komentar yang lebih nyaman. Jika Node.js mendukung pengabaian tipe, pendekatan seperti itu juga menjadi mungkin di JavaScript
Secara pribadi, ketidaknyamanan terbesar saat memakai JSDoc adalah sintaks import, tetapi itu berubah sejak TypeScript 5.5 sehingga sekarang tidak lagi menjadi masalah
Namun, beberapa bundler sudah melakukan ini dengan kompiler tidak resmi seperti SWC, dan Node juga sedang menguji SWC untuk fitur ini
Type hint bukan sekadar komentar sederhana, tetapi juga petunjuk bagi IDE agar bisa menampilkan autocomplete yang lebih baik, seperti halnya nama
Menurut saya, ini memang seharusnya menjadi bagian dari spesifikasi bahasa
Saya penasaran bagaimana ekosistem NPM akan bereaksi jika fitur ini menjadi default, bukan lagi berada di balik flag. Apakah para kontributor masih akan membangun versi CJS dan ESM saat mendistribusikan modul NPM, atau mereka akan cukup menambahkan
engine: nodejs >= 25dipackage.jsondan melewati tahap build?Secara pribadi, saya akan lebih suka jika modul NPM yang memiliki sumber TS berhenti mendistribusikan
dist/.cjs, karena akan membuat lebih jelas di mana debugger danconsole.logseharusnya ditempatkan. Dari sudut pandang kontributor NPM juga, godaan untuk menghapus tahap build akan besarNamun jika hanya satu dependensi saja mulai mendistribusikan file TS, asumsi bahwa “semua orang menerima file TS” bisa cepat menyebar. Begitu Node.js mengeluarkan ini dari flag eksperimen opt-in, seluruh komunitas tampaknya akan secara implisit berharap konsumen menerima file TS
Jika begitu, dalam beberapa bulan Firefox dan Safari juga akan mendapat tekanan untuk menerimanya, dan semua kompiler JS pada akhirnya akan dipaksa membuang anotasi tipe TS
Secara pribadi saya juga tidak masalah dengan itu. Bahkan pihak yang memakai TS pun saat ini memasukkan tahap transformasi ke modul NPM untuk mengubah kode TS menjadi JS dan
.d.tsdemi mendukung pengguna JS hipotetis tertentu. Namun jika Node menerima file.ts, tahap transformasi seperti itu bisa dihapus tanpa disadari, jadi saya penasaran mekanisme apa yang akan mencegah penerbit NPM berhenti mendistribusikan filejs/d.tstanpa sadar bahwa ada yang rusakDi sana kode TypeScript bisa diunggah tanpa tahap build, dan saat pengembang lain memasangnya, mereka bisa melihat sumber TypeScript asli alih-alih JavaScript hasil transformasi
.tsdi dalamnode_modulestidak didukung. Ini adalah salah satu batasan utama untuk mencegah ekosistem rusak.cjsdan.mjsuntuk npm, jadi kemungkinan mereka akan mendistribusikan ketiga versinyaJika proyeknya baru dan ditulis dari nol, mungkin saja hanya mendistribusikan TypeScript tanpa transformasi
Koreksi: menurut komentar saudara dari satanacchio, yang tampaknya penulis PR sekaligus anggota komite pengarah teknis Node.js, dukungan TS hanya berlaku untuk item tingkat teratas dan tidak diterapkan pada library di dalam
node_modules.tsyang merupakan source code saya ke npm, tetapi tim TypeScript sangat menentangnya karena masalahtsconfigdan performa. Meski begitu, saya tetap berharapMungkin suatu hari Node akan bisa melakukan refleksi runtime atas tipe-tipe ini di JS
Itu akan menjadi keuntungan besar. Di Python, tipe bisa direfleksikan, sehingga alat hebat seperti pydantic bisa menghasilkan pemeriksaan dari tipe
Dengan satu notasi standar saja, kita bisa mendapatkan pemeriksaan tipe, validasi data runtime, pembuatan API, dan pembuatan dokumentasi API
Saat ini di JS, alat seperti Zod pada dasarnya harus menemukan ulang apa yang TypeScript sudah lakukan, seperti
const mySchema = z.string();z.string()di Zod tidak hanya memberikan keamanan tipe seperti TypeScript. TypeScript memberikan pemeriksaan tipe saat waktu kompilasi, sedangkan Zod menambahkan validasi dan parsing runtimez.string()mengubahmySchemamenjadi skema fungsional yang bisa dipakai untuk parsing dan validasi.mySchema.parse("some data")akan berhasil, sedangkanmySchema.parse(321)akan melempar exceptionSaya pernah memakainya di tempat yang membutuhkan validasi runtime dan pemeriksaan di dalam proses, dan hasilnya cukup baik; Anda juga bisa mengekstrak tipenya seperti
const A = z.string(); type A = z.infer; // stringArtinya, jika Anda mendefinisikan tipe terlebih dahulu di Zod lalu menginferensi tipenya dari sana, Anda mendapatkan pemeriksaan tipe saat kompilasi sekaligus saat runtime. Memang ini bisa terasa berlebihan untuk codebase kecil yang bergerak cepat, tetapi cukup berguna dalam situasi yang memerlukan validasi dalam proses, dan beban kerjanya juga tidak terlalu besar
Namun TypeScript memang mengizinkan plugin. Meskipun jarang dipakai, plugin bisa menambahkan fitur lain ke bahasa yang kemudian ditransformasikan menjadi JavaScript hasil akhir
Ada plugin terkait tipe runtime bernama Typia, yang memungkinkan signature tipe TypeScript dipakai saat runtime dalam guard seperti
assert(myValue). Plugin ini mencegat pemanggilan fungsi tersebut dan menghasilkan deretanifyang exhaustive di JavaScript hasil transformasi untuk memeriksa sifat argumen yang diberikanSepertinya ini tidak akan menjadi bagian dari bahasa dalam 4~6 tahun ke depan, tetapi library yang memungkinkan hal semacam ini sudah ada sekarang
Yang benar-benar dibutuhkan adalah sistem tipe yang sound, tetapi TS sengaja tidak sound. Kita butuh sistem tipe yang tidak mengizinkan praktik coding buruk seperti TS, dan yang memaksa desain yang memungkinkan program berjalan lebih cepat. Kita butuh sistem tipe Hindley-Milner
Jika ingin membuat modul menjadi kode bertipe, bisa saja cukup dengan menambahkan
"use type". Mode ini harus melarang bagian-bagian buruk seperti type coercion, serta mencegah hal-hal yang merusak performa seperti mengubah bentuk objek atau tipe nilai, atau membuat array yang mencampur nilai apa punData yang masuk dari modul tanpa tipe harus ditransformasikan, atau jika tidak bisa ditransformasikan maka melempar error; dengan begitu kompiler bisa melakukan optimasi mendalam pada kode bertipe dengan jaminan tipe yang lebih kuat dan tanpa risiko bailout di tengah jalan
ValueError, atau apakah sebuah objek adalah instance dariSomeClass? Saya masih pemula di TS, jadi saya mengira selain array, object, angka, dan string, tipe lain sebenarnya tidak ada di JS, dan Zod atau fungsi type guard hanya mengembalikan object biasa pada level “percaya saja”Pengalaman pengembang Bun di area ini berada pada tingkat yang cukup belum pernah ada sebelumnya, dan sekarang sebagian besar use case sudah tercakup atau setidaknya Bun tidak lagi crash saat menulis skrip yang dijalankan dengan
bun runSementara itu, Node bahkan tidak bisa dikonfigurasi agar tidak mewajibkan ekstensi pada import, dan
tscjuga tidak bisa otomatis menambahkan ekstensi.jspada hasil kompilasi, jadi Anda harus menambahkan bundlerDukungan TypeScript native mungkin akan memperbaiki banyak ketidaknyamanan kecil ini, tetapi bahkan jika sudah stabil, sulit membayangkan pengalaman pengguna atau performanya bisa menandingi Bun
Pengalaman pengembang dan tooling-nya juga kelas atas. Deno juga bisa melakukan type checking dan kalau tidak salah menyertakan TSC
Bun memang sedang ramai dibicarakan, tetapi untuk pekerjaan serius saat ini Deno jelas pilihan yang lebih baik. Meski begitu, visi dan eksekusi Bun tetap mengesankan dan ini hal yang baik bagi para pengembang
bun installgagal sehingga tidak pernah benar-benar berfungsi: https://github.com/search?q=repo%3Aoven-sh%2Fbun+bun+install...Saya sudah lama menginginkan runtime TypeScript dan juga sangat menyukai TypeScript, tetapi lucu juga setelah lama meninggalkan Java, saya malah akhirnya mencari sesuatu yang jauh lebih mirip Java
Pada akhirnya, sepertinya yang kita inginkan adalah Java dengan JIT, sistem tipe yang lebih kaya, dan tipe bertahap. Ekosistem npm juga punya banyak kekurangan, tetapi memakai library di ekosistem ini terasa jauh lebih ringan dan lebih menyenangkan
Menariknya, Rust berada di ujung lain spektrum bahasa, tetapi kadang memberi kesan yang mirip
Edit: Istilah JIT tadi kurang tepat. Saya menulis JIT dengan asal, tetapi yang saya maksud adalah perbedaan waktu startup dan runtime saat menjalankan sesuatu di JVM dan V8. Java terasa berat, sedangkan ekosistem JavaScript terasa jauh lebih lincah
Saya juga sama sekali tidak merasa TypeScript lebih dekat ke Java. Keduanya hanya berbagi nama yang keliru “Javascript” dan dukungan untuk pemrograman imperatif; selebihnya menurut saya sangat berbeda
Tetapi satu hal dari Java yang saya rindukan di TypeScript adalah refleksi tipe saat runtime. Di ekosistem TypeScript ada banyak sekali cara untuk menyiasatinya, tetapi semuanya terasa agak jelek
AoT juga tidak masalah, dan akan bagus kalau ada opsi single binary. Idealnya tanpa runtime dan bisa melakukan eliminasi cerdas. Akan lebih bagus lagi kalau bisa juga berjalan dengan JIT di browser
Saya juga ingin fitur kemudahan dari compiler dan type checker seperti exhaustive pattern matching
Fitur Deno yang saya sukai mulai masuk langsung ke Node. Bagus sekali
Mungkin sekarang saya tidak perlu selalu memasang esbuild hanya untuk menghapus tipe. Saya menantikan menulis skrip dalam TypeScript menjadi jauh lebih mudah
Belakangan ini saya cenderung memilih Python untuk skrip sekali pakai, tetapi dari sisi tipe, secara pribadi saya menilai TypeScript lebih baik daripada Python. Terutama untuk skrip besar yang dilihat lagi beberapa bulan kemudian, manfaat tipe sangat terasa
ts-node, tetapi secara pribadi saya lebih sukatsxhttps://github.com/privatenumber/tsx
Ini benar-benar sebulan yang penuh kejadian bagi Node. Pertama node:sqlite ditambahkan di v22.5.0, dan sekarang dukungan TypeScript juga sedang masuk. Saya suka arah yang diambil Node
Saya penulis PR-nya. Silakan tanya apa saja
Sudah lama saya mulai memakai Node.js untuk pekerjaan backend, dan rasanya ada banyak kelebihan dibanding menulis kode dengan PHP tanpa terlalu membawa banyak masalah dari Java.
Namun Node agak terasa kasar, dan seperti bahasa yang perlu ditempeli ini-itu untuk menjadi bahasa yang saya inginkan. Pada akhirnya saya mulai memakai Go, yang jauh lebih mudah digunakan dan, meski kadang jauh lebih bertele-tele, penulisan kodenya jadi lebih sederhana berkat keamanan tipe
TypeScript tampak seperti pilihan yang bagus, tetapi pada akhirnya tetap hanya tambahan lain. Saya kurang paham nilai apa yang didapat jika memakai TypeScript alih-alih Go. Memiliki tipe yang jelas memang bagus, tetapi itu tidak menyelesaikan masalah-masalah bahasa lain yang sudah diselesaikan di Go. Deno juga menyelesaikan sebagian
Kelebihan besar Node dibanding Go adalah bisa membuat prototipe dengan cepat, tetapi kalau memakai TypeScript rasanya kelebihan itu cukup banyak berkurang. Jadi sulit menilai apakah ini kemajuan yang baik, atau justru membuat Node kehilangan sifat yang dulu menjadikannya pilihan yang bagus
Dari ungkapan “tambalan”, masalahnya mungkin bukan pada bahasanya sendiri, melainkan pada tidak adanya framework yang opinionated seperti Django yang mengelola semuanya secara bawaan. Saya suka memakai Django, tetapi memang jadi sedikit lebih sulit untuk keluar dari jalur yang sudah ditentukan
cdktfkarena punya pengalaman frontend sebelumnya, dan itu tampak seperti pilihan yang lebih masuk akal daripada Go