- Node.js PR #53725 birleştirildi ve
--experimental-strip-types bayrağıyla TypeScript dosyalarını çalıştırma desteği deneysel olarak eklendi
- Bu özellik, TypeScript kaynağındaki tip sözdizimini kaldırarak onu JavaScript kaynağına dönüştürüyor; dönüşüm sırasında tip denetimi yapılmıyor
- İlk uygulama,
Enum, namespaces gibi TypeScript’e özgü özellikleri dönüştürmediği için yalnızca tiplerin kaldırılmasıyla JavaScript’e dönüşen kodlarla sınırlı
- Uygulama için
@swc/wasm-typescript seçildi; nedeni, Node.js araç zincirine Rust veya Go eklemeyi gerektirmeyen sadeliği
- Tartışmalarda ESM’in zorunlu dosya uzantısı kuralları,
.js import’unun gerçekte .ts dosyasını işaret ettiği TypeScript pratiği, source map’ler ve hata yığını konum maliyeti başlıca kısıtlar olarak ele alındı
--experimental-strip-types nasıl çalışıyor
--experimental-strip-types etkinleştirildiğinde Node.js TypeScript dosyalarını çalıştırabiliyor
- Node.js, TypeScript kaynak kodunu JavaScript kaynak koduna transpile ediyor
- Transpile sürecinde tip denetimi yapılmıyor ve tip bilgisi atılıyor
- Örnek şu şekilde
const foo: string = "foo";
const foo = "foo";
Neden yalnızca tip kaldırma seçildi ve ilk kısıtlar
- Bu PR’ın odağı, TypeScript sözdizimi içinde tip sözdizimini kaldırmak
- Diğer çalışma zamanları,
enum gibi JavaScript’te olmayan TypeScript’e özgü özellikleri JavaScript’e dönüştürebiliyor
- Bu PR’ın ilk uygulaması böyle dönüşümler yapmıyor
Enum kullanılamıyor
namespaces kullanılamıyor
- Diğer TypeScript’e özgü özellikler de dönüşüm kapsamına dahil değil
- Uygulama ayrıntıları ve kısıtlar için PR değişikliklerindeki
typescript.md dosyasına bakılması isteniyor
Uygulama aracı olarak @swc/wasm-typescript seçildi
@swc/wasm-typescript küçük bir paket ve bir wasm dosyası ile bunu bağlayan JavaScript dosyalarından oluşuyor
- Diğer araçlar, Node.js araç zincirine Rust veya Go eklenmesini gerektiriyordu
- SWC, Deno’da da aynı amaçla kullanılıyor ve PR yazarı bunu kanıtlanmış bir seçenek olarak görüyor
- İleride bu özelliğin yerel katmanda uygulanabileceği düşünülüyor
- Bu PR, nodejs/loaders#217 konusuna atıfta bulunuyor
import çözümleme ve uzantı tartışması
import foo from "./foo" gibi uzantısız import desteklenmiyor
- Node.js ESM’de mandatory file extensions kuralı var; bu yüzden uzantısız import desteğinin olmaması kasıtlı bir davranış olarak ele alınıyor
- TypeScript modül kod tabanlarında, gerçek dosya
.ts olsa bile import satırlarında .js uzantısının kullanılması yaygın bir pratik olarak belirtildi
- Örnek:
import foo from './foo.js'
- Gerçek dosya sisteminde
./foo.js olmayıp yalnızca ./foo.ts bulunabiliyor
- PR yazarı bu konunun ileride yinelemeli çalışmalarla ele alınabileceğini, uzantı tahmini için ek dosya sistemi kontrolleri ve sezgisel kurallar gerektiğini düşünüyor
./foo.js yoksa ./foo.ts kontrol edilir
./foo.ts yoksa ./foo.js kontrol edilir
- Bu tartışma nodejs/loaders#208 altında takip ediliyor
Kaynak konumu, source map’ler ve hata yığını
- İncelemede, hata yığınında doğru kaynak konumunun kısa vadede gerekli olduğu görüşü dile getirildi
- Olası bir yöntem, tip kaldırma sürecinde kaynak konumlarını değiştirmeyerek source map üretimi ve eşlemesini önlemek
- Source map’lerin bellek kullanımı ve performans açısından bir maliyeti olduğu ve bunun basit olmadığı belirtildi
- PR yazarı, SWC zaten source map desteği sunduğu için bunu etkinleştiren bir bayrak eklenebileceğini düşünüyor
- Ayrıca SWC’den, kaldırılan sözdizimini boşluklarla değiştirerek özgün hata yığınını bozmayan bir seçenek istenebileceği belirtiliyor
Kararlılık öncesi kalan tasarım konuları
- TypeScript desteği iki eksene ayrılıyor
- tip sözdizimini kaldırmak
.ts dosyalarını kabul edecek şekilde çözümleme kurallarını ayarlamak
- Çözümleme kurallarının değiştirilmesinin mevcut TypeScript loader’larıyla çakışabileceğine dair kaygılar dile getirildi
- PR yazarı, bu PR’da çözümleme kuralı override edilmediğini ve dosya uzantısının gerekli olduğunu söylüyor
allowImportingTsExtensions ile import './file.ts' biçimi desteklenebilir; bunun Deno ile de uyumlu olduğu ifade ediliyor
- Aynı kaynak dosyayı doğrudan çalıştırıp derleme araçlarıyla JavaScript çıktısı da üretmek için
file.tsyi file.jsye çevirme sorumluluğunu build aracının üstlenebileceği düşünülüyor
Birleştirme ve sonraki çalışmalar
- PR, 24 Temmuz 2024’te
nodejs:main dalına birleştirildi
- Değişiklik ölçeği 8 commit, 89 dosya, 2.190 satır ekleme ve 25 satır silme
semver-minor, experimental, module, esm, notable-change gibi etiketler eklendi
- Web sitesindeki TypeScript rehber sayfasında bu özellikten söz edilip edilmeyeceği tartışıldı ve ilgili güncelleme PR’ı da bağlandı
- Dağıtım metadata’sına, Node ikilisinin tip kaldırma için kullandığı TypeScript sürümünü ekleme fikri de sonraki bir konu olarak tartışılıyor
1 yorum
Hacker News görüşleri
TypeScript türlerinin kaldırılması, TypeScript sözdizimi olmadan mümkün değil. Tür kaldırma, token düzeyinde bir işlem değil ve TypeScript sözdizimi sürekli değişiyor.
Örneğin
foo < bar & baz > ( x ), TypeScript 1.5’tebar&bazgeçerli bir tür ifadesi olmadığı için(foo (x))gibi ayrıştırılıyordu; ancak kesişim türü operatörü eklendikten sonrafoo<(bar & baz)>(x)olarak ayrıştırılıpfoo(x)biçiminde belirsizlikten arındırıldı.En yeni TypeScript özelliklerini kullanmaya devam etmek için JS’ye derlemek ya da Node sürümünü sürekli güncel tutmak gerekiyor; Node LTS’te kalmayı tercih eden ekipler için bu kabul etmesi zor bir ödün olabilir.
Çekirdekte kararlı bir sürüm tutulup, TypeScript yeni özellikler veya kırıcı değişiklikler çıkardığında ya da kullanıcı yeni deneysel özellikleri kullanmak istediğinde bunun NPM üzerinden ayrı yükseltilebilmesi şeklinde.
Böylece kullanıcılar sabitlenmeden, Node.js sürümünün 3 yıllık ömrü boyunca belirli bir TypeScript sürümü desteklenebilir: https://github.com/nodejs/loaders/issues/217
Son büyük sözdizimi değişikliği muhtemelen 2.8’deki koşullu türlerdi; tür konumlarına üçlü
ifoperatörüne benzer bir sözdiziminin girdiği dönem. Tür denetimi de yapılacaksa tür modeli 2.x’ten sonra çok değişti, ancak sözdizimi genel olarak kararlıydı ve TypeScript’teki yeniliklerin çoğu tür modeli ve tür çıkarımı tarafındaydı.Henüz erken aşamada, Stage 1’de olsa da, tür denetimi değil tür kaldırma amacıyla TypeScript tür sözdiziminin önemli bir bölümünü standartlaştırmaya yönelik bir girişim de var: https://github.com/tc39/proposal-type-annotations
En yeni V8 veya Node özellikleriyle pek ilgilenmeyip LTS’te kalan ekiplerin, en yeni TypeScript özellikleriyle de daha az ilgilenme olasılığı yüksek.
Node.js TypeScript dosyalarını doğrudan çalıştırabiliyorsa, TypeScript derleyicisi tür kaldırma ve JavaScript’e dönüştürme yerine yalnızca tür denetleyicisi olarak kullanılabilir. Bu, Python’da tür denetleyicilerinin türleri denetleyip olduğu gibi bırakmasına, yorumlayıcının ise tür ipuçlarını yok saymasına benziyor.
İlginç biçimde Python’da aynı tür ipucu sözdizimini kullanan ama semantiği farklı olan birden fazla popüler tür denetleyicisi ortaya çıktı. Buna karşılık JavaScript’te TypeScript fiilen tek popüler tür denetleyicisi olmuş gibi görünüyor.
Python’da tür denetimi yapmadan, kaynakta yalnızca türleri yazarak daha kullanışlı bir yorum sözdizimi gibi kullananların da olduğunu duydum. Node.js türleri yok saymayı desteklerse JavaScript’te de böyle bir yöntem mümkün olur.
Kişisel olarak JSDoc kullanımındaki en büyük rahatsızlığım import sözdizimiydi; TypeScript 5.5’ten sonra bu değişti ve artık sorun olmaktan çıktı.
Ancak bazı bundler’lar bu iş için zaten SWC gibi gayriresmî derleyiciler kullanıyor ve Node da bu özellikte SWC’yi deniyor.
Tür ipuçları yalnızca basit yorumlar değil; adından da anlaşılacağı gibi IDE’nin daha iyi otomatik tamamlama sunabilmesi için ipuçlarıdır.
Bunun dil spesifikasyonunun bir parçası olması gerektiğini düşünüyorum.
Bu özellik bir bayrağın arkasında kalmayıp varsayılan olduğunda NPM ekosisteminin nasıl tepki vereceğini merak ediyorum. Katkı verenlerin NPM modülleri yayımlarken hâlâ CJS ve ESM sürümlerini derleyip derlemeyeceğini, yoksa
package.jsoniçine yalnızcaengine: nodejs >= 25ekleyip derleme adımını atlayıp atlamayacağını bilmiyorum.Kişisel olarak, TS kaynaklarına sahip NPM modülleri
dist/.cjsdağıtmayı bırakırsa, debugger’ı veconsole.log’u nereye koyacağımız netleşeceği için bunun daha iyi olacağını düşünüyorum. NPM katkıcıları açısından da derleme adımını kaldırmanın cazibesi büyük olacaktır.Ancak tek bir bağımlılığın bile TS dosyası dağıtması, “herkes TS dosyalarını alır” varsayımının hızla yayılmasına yol açabilir. Node.js bunu opt-in deneysel bayrağın dışına çıkardığı anda, tüm topluluk tüketicilerin TS dosyalarını kabul etmesini örtük olarak beklemeye başlayacak gibi görünüyor.
Böyle olursa birkaç ay içinde Firefox ve Safari de bunu kabul etmeleri için baskı altında kalır ve tüm JS derleyicileri TS tip açıklamalarını atmak zorunda kalır.
Kişisel olarak buna da itirazım yok. Çünkü TS kullanan taraf da, varsayımsal JS kullanıcılarını desteklemek için TS kodunu JS ve
.d.ts’ye dönüştüren bir adımı NPM modüllerine koyuyor. Ama Node.tsdosyalarını kabul ederse bu dönüştürme adımı fark edilmeden kaldırılabilir; bu yüzden NPM yayımcılarınınjs/d.tsdosyalarını dağıtmayı bırakıp bozulduğunu fark etmemesini engelleyecek mekanizmanın ne olacağını merak ediyorum.Derleme adımı olmadan TypeScript kodu yüklenebiliyor ve başka bir geliştirici kurduğunda dönüştürülmüş JavaScript yerine özgün TypeScript kaynağını görebiliyor.
node_modulesiçindeki.tsdosyalarının çalıştırılması desteklenmiyor. Bu, ekosistemi bozmamak için getirilen başlıca kısıtlardan biri..cjsve.mjs’ye dönüştürülüyor; muhtemelen üç sürümün tamamı dağıtılacak gibi görünüyor.Sıfırdan yazılan yeni bir proje olsaydı yalnızca TypeScript dağıtıp dönüştürme yapmayabilirlerdi.
Düzenleme: PR yazarı ve Node.js Teknik Yönlendirme Komitesi üyesi gibi görünen satanacchio’nun kardeş yorumuna göre TS desteği üst seviye girdiler içindir ve
node_modulesiçindeki kütüphanelere uygulanmıyor..ts’yi npm’de yayımlamak istiyorum, ancak TypeScript ekibitsconfigsorunları ve performans sorunları nedeniyle buna çok karşı çıkmıştı. Yine de umutluyum.Belki bir gün Node, JS içinde bu tipleri runtime reflection ile yansıtabilir.
Bu çok büyük bir kazanım olur. Python’da tipler yansıtılabildiği için pydantic gibi harika araçlar tiplerden doğrulamalar üretebiliyor.
Tek bir standart gösterimle tip denetimi, runtime veri doğrulama, API üretimi ve API dokümantasyonu elde edilebiliyor.
Bugün JS’de Zod gibi araçlar
const mySchema = z.string();gibi şeylerle TypeScript’in zaten yaptığı işi fiilen yeniden icat etmek zorunda kalıyor.z.string()ifadesi yalnızca TypeScript benzeri tip güvenliği sağlamaz. TypeScript derleme zamanında tip denetimi sağlar, Zod ise runtime doğrulama ve ayrıştırma ekler.z.string(),mySchema’yı ayrıştırma ve doğrulama yapabilen işlevsel bir şemaya dönüştürür.mySchema.parse("some data")başarılı olur,mySchema.parse(321)ise istisna fırlatır.Runtime doğrulama ve süreç içi kontrol gereken yerlerde kullandım; oldukça iyi çalıştı ve
const A = z.string(); type A = z.infer; // stringgibi tip de çıkarılabiliyor.Yani Zod’da önce tipi tanımlayıp oradan tipi çıkarırsanız hem derleme zamanında hem de runtime’da tip denetimi elde edersiniz. Hızlı hareket eden küçük kod tabanları için fazla gelebilir, ama süreç içi doğrulama gereken durumlarda oldukça kullanışlı ve iş yükü de büyük değil.
Bununla birlikte TypeScript eklentilere izin veriyor. Çok yaygın kullanılmasa da dile, sonuçta JavaScript’e dönüştürülen başka özellikler eklenebiliyor.
Runtime tiplerle ilgili bir eklenti olarak Typia var;
assert(myValue)gibi guard’larda TypeScript tip imzalarının runtime’da kullanılmasını sağlıyor. Bu fonksiyon çağrısını yakalayıp dönüştürülmüş JavaScript içinde aktarılan değişkenin özelliklerini kontrol eden exhaustiveififadeleri üretiyor.Önümüzdeki 4–6 yıl içinde bunun dilin bir parçası olacağını sanmıyorum, ama bugün bile bu işi yapmayı sağlayan kütüphaneler mevcut.
Aslında sağlam bir tip sistemi gerekiyor, ama TS bilinçli olarak sağlam değil. TS gibi kötü kodlama pratiklerine izin vermeyen, hızlı programlar yazdıracak tasarımları zorunlu kılan bir tip sistemi gerekiyor. Hindley-Milner tip sistemi gerekiyor.
Bir modülü tipli kod yapmak istiyorsanız
"use type"eklemek gibi bir yöntem yeterli olur. Bu mod, tip zorlaması gibi kötü kısımları yasaklamalı; nesne şekillerini veya değer tiplerini değiştirmek ya da her tür değeri karıştıran diziler oluşturmak gibi performansı bozan unsurları engellemelidir.Tipsiz modüllerden gelen veriler dönüştürülmeli ya da dönüştürülemiyorsa hata fırlatmalı; böylece derleyici daha güçlü tip garantileri ve bail-out riski olmadan tipli kodu derinlemesine optimize edebilir.
ValueErroralt sınıfı olup olmadığını ya da bir nesneninSomeClassörneği olup olmadığını bilebileceği anlamına gelip gelmediğini merak ediyorum. TS’de yeniyim; dizi, nesne, sayı ve string dışında JS’de tip olmadığını, Zod ya da type guard fonksiyonlarının ise “bana güven” düzeyinde sıradan nesneler döndürdüğünü sanıyordum.Bun’ın geliştirici deneyimi bu alanda epey benzeri görülmemiş bir seviyede; artık kullanım senaryolarının çoğu kapsanıyor ya da
bun runile çalıştırma betikleri yazarken Bun çökme yapmıyorBuna karşılık Node, import’larda uzantı istemeyecek şekilde bile ayarlanamıyor;
tsc’nin derleme çıktısına otomatik olarak.jsuzantısı eklemesi de sağlanamıyor, bu yüzden bir bundler eklemek gerekiyorYerel TypeScript desteği bu küçük rahatsızlığı epey giderecek, ama kararlı hâle gelse bile kullanıcı deneyimi veya performans açısından Bun’la başa baş olacağını hayal etmek zor
Geliştirici deneyimi ve araçları da en üst düzeyde. Deno tip denetimi de yapabiliyor ve hatırladığım kadarıyla TSC’yi bundle ediyor
Bun çok ses getiriyor, ama ciddi işler için şu anda Deno açıkça daha iyi bir seçenek. Yine de Bun’ın vizyonu ve uygulama hızı etkileyici; geliştiriciler için iyi bir şey
bun installçalıştırmak başarısız olduğu için bir kez bile düzgün çalışmadı: https://github.com/search?q=repo%3Aoven-sh%2Fbun+bun+install...Uzun zamandır bir TypeScript runtime’ı istiyordum ve TypeScript’i de gerçekten seviyorum; ama yıllar önce Java’yı bırakıp sonunda Java’ya çok daha yakın bir şey arar hâle gelmem komik
Sonuçta istediğimiz şey JIT, daha zengin bir tip sistemi ve kademeli tiplere sahip Java’ymış gibi görünüyor. npm ekosisteminin de pek çok eksiği var, ama bu ekosistemde kütüphane kullanmak çok daha az zahmetli ve daha eğlenceli
Şaşırtıcı biçimde Rust, dil spektrumunun diğer ucunda olsa da benzer bir his de verebiliyor
Düzeltme: JIT ifadesi uygun değildi. Tembelce JIT yazdım; aslında JVM ve V8’de bir şey çalıştırırken başlangıç süresi ve runtime farklarından bahsetmek istemiştim. Java ağır hissettiriyor, JavaScript ekosistemi ise çok daha çevik geliyor
TypeScript’in Java’ya daha yakın olduğundan da hiç emin değilim. İkisinin paylaştığı şeyler “Javascript” şeklindeki yanlış adlandırma ve imperative programlama desteği kadar; geri kalanı bence çok farklı
Yine de Java’da olup TypeScript’te özlediğim şey runtime tip yansıması. TypeScript ekosisteminde bunu aşmanın sayısız yolu var, ama hepsi bana biraz çirkin görünüyor
AoT de olur; tekil binary seçeneği olsa iyi olur. İdeal olarak runtime olmasın ve akıllı eleme yapılabilsin isterim. Tarayıcıda JIT ile de çalışırsa daha da iyi
exhaustive pattern matching gibi derleyici ve tip denetleyici kolaylıklarını da istiyorum
Sevdiğim Deno özellikleri doğrudan Node’a geliyor. Çok iyi
Artık tipleri kaldırmak için her zaman esbuild kurmam gerekmeyebilir. TypeScript ile betik yazıp kullanmanın çok daha kolaylaşacağını düşündüğüm için heyecanlıyım
Son zamanlarda tek seferlik betikler için Python’ı tercih ediyordum, ama tipler açısından kişisel olarak TypeScript’in Python’dan daha iyi olduğunu düşünüyorum. Özellikle birkaç ay sonra yeniden bakılan büyük betikler tiplerden ciddi fayda görüyor
ts-nodeda var ama kişisel olaraktsx’i tercih ediyorumhttps://github.com/privatenumber/tsx
Node için gerçekten olaylı bir ay oldu. Önce v22.5.0’da node:sqlite eklendi, şimdi de TypeScript desteği geliyor. Node’un gittiği yön hoşuma gidiyor
PR’ın yazarıyım. İstediğinizi sorabilirsiniz
Uzun zaman önce backend işlerinde Node.js kullanmaya başladım; PHP ile kod yazmaya göre birçok avantajı var gibi görünüyordu ve Java’nın sorunlarının çoğunu da beraberinde getirmiyordu.
Ancak Node biraz kaba saba idi; istediğim dili oluşturmak için sağa sola bir şeyler eklemem gereken bir dil gibi hissettiriyordu. Sonunda Go kullanmaya başladım; kullanımı çok daha kolaydı ve bazen çok daha ayrıntılı olsa da tip güvenliği sayesinde kod yazmak basitleşti.
TypeScript iyi bir seçenek gibi görünüyordu ama sonuçta o da başka bir yama idi. Go yerine TypeScript kullanınca ne değer elde ettiğimi pek bilmiyorum. Açık tiplerin olması güzel, ama Go’da çözülmüş olan dilin diğer sorunlarını çözmüyor. Deno da bunların bir kısmını çözüyor.
Node’un Go’ya göre büyük avantajı hızlı prototip çıkarabilmek; TypeScript kullanınca bu avantajın epey azaldığını düşünüyorum. Bu yüzden bunun iyi bir ilerleme mi, yoksa Node’u iyi bir seçenek yapan özellikleri kaybettiren bir şey mi olduğuna karar vermek zor.
“Yama” ifadesine bakınca sorun dilin kendisinden çok, Django gibi her şeyi varsayılan olarak yöneten görüşlü bir framework eksikliği olabilir. Django kullanmayı seviyorum, ama belirlenmiş yolun dışına çıkmak biraz daha zor.
cdktfile birlikte kullanıyoruz; Go’ya göre daha mantıklı bir tercih gibi görünmüştü.