1 puan yazan GN⁺ 2023-07-09 | 1 yorum | WhatsApp'ta paylaş
  • TypeScript’in çalışma zamanı tip bilgisi üretmesi gerektiğini savunan ve bu sorunu aşmak için kullanılan Type Mapping, Code Generation / External Tool ve Adapter projelerini bir araya getiren bir liste
  • Temel sorun, yansıtıcı bir tip sistemi olmadan serileştirme ve doğrulamanın ele alınmasının sonsuz boilerplate ya da şema dosyası tabanlı özel kod üretimini gerektirmesi
  • Geçici çözüm olarak io-ts ve zod gibi araçlar öneriliyor; ancak tiplerin her kütüphane için yeniden tanımlanması gerekiyor ve bu kütüphaneler TypeScript’in tüm tip özelliklerini destekleyemiyor
  • TypeScript’in tip silme yaklaşımının, JavaScript projelerinin TypeScript bilgisi olmadan üretilmiş JavaScript’i kullanabilmesini sağlama avantajı kabul edilmekle birlikte, tip bilgisinin koddan ayrılmış bir başvuru tablosu biçiminde de üretilebileceği savunuluyor
  • Bunun dekoratörlerle çözülmemesi istenirken, interface kullanımı ve harici kütüphane tip desteği için typescript.generateRuntimeType<T>() gibi derleyicinin tanıdığı yüksek seviyeli fonksiyonlar, F# Type Providers ve C# Source Generators benzeri yaklaşımlar öneriliyor
  • İlgili mevcut tartışmalar arasında 8 yıllık GitHub issue bağlantısı veriliyor ve aynı sorunu yaşamış projelerin, çözümden bağımsız olarak listeye eklenmesi için PR göndermesi isteniyor

1 yorum

 
GN⁺ 2023-07-09
Hacker News yorumları
  • Ne istendiğini anlamak için açıklamayı yaklaşık 4 kez okumam gerekti; bu da özlü yazımın neden önemli olduğunu gösteren türden bir örnek
    Asıl talep çalışma zamanında tip güvenliği gibi görünüyor, ancak TypeScript uzun süredir JavaScript’in yerine geçen/ona eklenen bir çalışma zamanı olmayacağı çizgisini koruduğu için bunun pek olası olmadığı düşünülüyor. TypeScript’in rolü JS’ye derlemek ve çekilmek; sonrasında V8 vb. üzerinde olanlar kapsam dışı.
    “TypeScript çalışma zamanı tip bilgisi yaymalı” talebi, mevcut TypeScript’ten epey farklı yeni bir ürün istemeye daha yakın

    • Aslında doğrudan çalışma zamanı tip güvenliği istenmesinden çok, derleme zamanında tip yansıtması (reflection) ile değerler üretilmesi ve bu bilginin çalışma zamanında kullanılabilmesi isteniyor
      Örneğin rastgele bir arayüz ve nesne alıp doğrulayan genel amaçlı bir validate fonksiyonu yazabilmek güzel olurdu. Derleme zamanı yansıtmasıyla tipe göre JS doğrulama kodu üretmek ya da çalışma zamanında T’yi argüman olarak geçirip karşılaştırmak mümkün olabilir, fakat mevcut TypeScript felsefesiyle bunun zor olduğu düşünülüyor
    • Sadece başlığa bakınca bile bunun uzun zamandır istenen bir özellik olduğu anlaşılıyordu; daha resmi ve daha iyi desteklenen https://github.com/rbuckton/reflect-metadata benzeri bir şeyin talep edilmesine daha yakın
      TypeScript derleme sırasında tip bilgisi hakkında çok şey biliyor, ama derleme bitince bu bilgiyi atıyor. Bu bilgiyi bir dosyaya dışa aktarabilir ya da Reflect üzerinde metadata olarak bırakabilirken bunu atmaları, özellikle JavaScript’in “her şey nesnedir” doğası düşünülünce, üzücü bir kısıt gibi geliyor.
      Birebir TS tip güvenliği elde edilemese bile, getter/setter veya ES2015 Proxy ile bazı kontroller eklenebilir; tip bilgisinin çalışma zamanında kalması da çalıştırılabilir metadata olarak birçok ilginç olasılığın önünü açar
    • Bunun TypeScript bir derleyici olduğu için imkansız olduğu doğru değil. Tip bilgisini JS nesneleri olarak çıktıya yazıp çalışma zamanında sorgulayan bir yansıma kütüphanesinin desteklenmesi yeterli olur
      Zaten TS enumları JS nesneleri olarak çıktılanıyor ve çalışma zamanında sorgulanabiliyor, ama string literal union tipleri böyle değil. Ayrıca TypeScript tip koruma fonksiyonlarını destekliyor; dolayısıyla tip sistemindeki bilgiyi kullanarak bu tür fonksiyonları otomatik üretmek de çok zor görünmüyor
    • Kabaca göz gezdirince bile talep açıktı. İstenen şey, TypeScript’in tip silme sürecinde öğrendiği tip bilgisini üretilen JavaScript’in yanında ek bir kanal üzerinden dışa aktarması
      Bunu PDB dosyaları gibi bir benzetmeyle düşünebilirsiniz. TypeScript’in zaten sahip olup sonra attığı bir bilgi olduğu için tamamen yeni bir ürün gerekmiyor
    • README’nin üst kısmında “7 yıllık GitHub issue” bağlantısı var ve orada problem daha doğrudan anlatılıyor
      https://github.com/microsoft/TypeScript/issues/3628
  • TypeScript PM bakış açısından bu isteği anlıyorum. Veri doğrulamada çalışma zamanı tip denetimi sık sık gerekiyor ve bu boşluğu kapatmaya çalışan çok sayıda kütüphane var
    Ancak farklı tasarım kararları alan çok sayıda kütüphanenin bulunması, bu problemin net bir doğru cevabı olan çözülmüş bir mesele olmadığının göstergesi. TypeScript’in ilk tasarım döneminde de bunun farkındaydılar ve bence bu ilke zaman içinde iyi dayandı.
    Bunun yerine TypeScript, çalışma zamanı tip denetimi kütüphanelerinin fiilen yaptığı işleri tiplerle doğru ifade edebilecek kadar güçlü hale geldi; kullanıcılar da API’ler üzerinden tiplerden çalışma zamanı doğrulama mantığı kurabiliyor. Bu seviye makul bir esneklik gibi geliyor

    • Programlamaya başlayalı çok olmadı ama TypeScript’in neden daha gelişmiş kullanıcı tanımlı veri tipleri oluşturamadığını merak ediyorum
      Örneğin belirli bir aralıktaki sayılar ya da posta kodu desenini karşılayan string’ler için tip tanımlayabilen ve derleyicinin, normal fonksiyon gibi yazılmış doğrulama fonksiyonlarını kullanarak geçerliliği kontrol ettiği bir dil hayal ediyorum. Böyle bir özelliğin olmaması gereksiz karmaşıklıktan kaçınmaya yönelik bir tasarım kararı mı, yoksa performans gibi teknik kısıtlar mı var, merak ediyorum
    • TypeScript derleyicisinde resmi bir ön işleyici eklenti sistemi olsa faydalı olabilir
      Şu anda da buna ihtiyacı olanlar, tsc’ye vermeden önce tip bilgisinden çalışma zamanı nesneleri üreten bir ön işleyici yazabilir, ama çaba çok dağınık durumda. Resmi, eklenti tabanlı bir ön işleyici ve etrafında bir ekosistem olsa iyi bir çözüm bulunabilir
    • Microsoft, TypeScript eklentisi ya da üst düzey bir sarmalayıcı olarak MacroScript barındırsa bu sorun çözülebilir
      Kıvılcım bir kez çaksa topluluk bakımına yardımcı olur ve istemci üretiminden çalışma zamanı tip assertion’larına kadar çeşitli kod üretim ihtiyaçları karşılanabilir
    • Derlemeden sonra tip bilgisinin Class nesneleri üzerinde bırakılmasını öneren diğer teklif hakkında ne düşünüldüğünü merak ediyorum
  • Bunu yapmamanın bir nedeni var. TypeScript, JavaScript’in üzerinde bir runtime katmanına dönüşür ve JS’ye derlenen yeni bir dil olur
    Şu anki TypeScript, tip açıklamaları eklenmiş JavaScript’e daha yakın. JS’ye derlenen pek çok dil zaten var; öyle bir şey isteniyorsa onlardan biri kullanılabilir. Runtime tipi olan bir TypeScript isteyenler, JavaScript’ten çok Java/OOP tarzı kod yazmak istiyor gibi görünüyor; ama JavaScript dinamik tipli bir dil ve bu da onun avantajlarından biri

    • Bu şart değil. generateTypeInfo!() gibi bir makro, Foo tipini kodlayan bir JS nesnesine genişliyorsa yine okunabilir JavaScript’e derlenmiş olur
      Ama bu makro, “TS = tip açıklamalı JS’dir ve derleme sadece açıklamaları silmektir” özelliğini bozar. Çünkü Foonun yapısal tipini gerçekten hesaplamak gerekir.
      Ayrıca TypeScript tipleri yapısaldır; bu yüzden runtime’da nesne yapısını inceleyerek tipe dair bir miktar bilgi edinilebilir, ama bir string union’a ait olup olmadığı gibi silinmiş nominal bilgiler veya tip adları istenirse, TypeScript tip sisteminin Turing-tamlığı ve örtük yapısal dönüşümleri nedeniyle bu hızla zor bir probleme dönüşür
    • İkisi birden de mümkün. Lisp’teki homoiconicity gibi, kod ile verinin birbirine yakın olduğu bir dünya hayal edilebilir
      Ciddi konuşursak, runtime olmadan da tipleri veri olarak açığa çıkarırsanız reflection elde edebilirsiniz. Pek çok geliştiricinin bunu taklit etmeye uğraşmış olması, bunu yapmamanın daha çok anlamsız göründüğünü düşündürüyor
    • Bu mantığı pek anlayamıyorum. TypeScript zaten JS’ye derlenen yeni bir üstküme dil
      Runtime tipler, derleme için kullanılan tip sistemi ile veri doğrulama için kullanılan tip sistemini ayrı ayrı ve tekrar ederek sürdürme sorununu çözüyor; bunun OOP ile doğrudan ilgili olduğu da pek görünmüyor. Bu soruna geçici çözüm sunan kütüphaneler arasında tercih ettiğim io-ts de güçlü biçimde fonksiyonel programlama tarafına yaslanıyor
    • Yeterince büyük projelerde dinamik tipli diller iyi değil; NaN gibi beklenmedik değerlere sürekli takılıp düşülen, iç içe geçmiş bir felakete yakınlar
      Benim gördüğüm iş akışlarında TypeScript zaten JS’ye derlenen bir dil, dolayısıyla madem öyle, bu avantajı olabildiğince kullanmak daha iyi
    • TypeScript sadece tip açıklamaları eklenmiş JavaScript değildir. Bu, modlardan biri olabilir, ama eski JS yapılarını çıktı verebilmesi nedeniyle ortaya çıkan kod kaynak TS kodundan tamamen farklı da görünebilir
      Tip açıklamaları + Babel’e daha yakın; buna çok faydalı bir özellik daha eklemek iyi bir fikir. JSON.parse ile elde edilen bir stringi tipli bir yapıya güvenli biçimde dönüştürememek tuhaf ve diğer dillerde bu genelde mümkün
  • Aşağıdakilere geçmeden önce: bu, tartışmaya fazlasıyla değer geçerli bir konu ve burada nesnel olarak tek bir doğru cevap olduğunu düşünmüyorum
    TypeScript, Enumun nesne export etmesi istisnası dışında, JavaScript üzerinde isteğe bağlı bir katmandır ve TS kodu tipler silinince JS olur. Bu ilkenin çok dışına çıkılmadığı sürece, asıl talep tiplerden serializer/validator üreten bir kütüphaneye daha yakın görünüyor. Böyle kütüphaneler zaten çok ve sonuçta talep, bunlardan birinin resmî standart seçenek haline getirilmesi gibi duruyor.
    Kişisel olarak TypeScript’in çekirdek diline runtime reflection gelmesini istemem. Runtime’da yalnızca JavaScript olmasını, source map olmadan bile üretilen JS’nin okunabilir ve debug edilebilir kalmasını değerli buluyorum

    • Enum dışında da runtime kodu üreten istisnalar var ve bunların çoğu da yine hata olarak görülüyor. En belirgin örnekler module ve namespace; bunlar runtime yapılarıydı
      Yine de son birkaç yılda bunlar daha çok TypeScript’in kendi içinde kullanıldı ve TypeScript de son dönemde bundan uzaklaşıyor. Bir diğer oldukça popüler istisna da parameter properties; constructor parametrelerinden sınıf üyesi tiplerini tanımlayan bir sözdizimi ve tekrarlı boilerplate’i azalttığı için daha az tepki çekmiş gibi görünüyor
    • “TS kodu dönüşüm olmadan JS olur” sözü, dili ve tip gösterimini bütünüyle bu şekilde ele alırsanız söylenebilir
  • TypeScript tanrılarına yalvarmak yerine, JavaScript tarafıyla anlaşıp tip kontrolünü JS’ye koymak daha iyi olmaz mı diye düşünüyorum
    Runtime tipi gerekiyorsa type guard kullanılır; sık gerekiyorsa da io-ts veya zod ile tipler validator/codec/schema olarak yazılır. JavaScript için üzerinde uzlaşılmış bir yöntem oluşana kadar TS spesifikasyonunun, tip denetleyicisinin ve topluluğun runtime doğrulamayı sırtlanması gerektiğini düşünmüyorum

    • Mükemmel olmasa da zod ile schema ve validator yazıp oradan tip türetme yaklaşımından oldukça memnunum. Doğrulamanın tip değişimleriyle birlikte evrilmesi hoşuma gidiyor
      Bazıları bunun dilin içine girmesi gerektiğini düşünüyor, ama kütüphaneler arasında tartışmalı birçok tasarım tercihi var; bu yüzden uygulamayı proje ihtiyaçlarına göre seçmek aslında daha iyi olabilir.
      Yine de zod runtime doğrulaması ve schema tabanlı tip türetme gibi kalıplar, ts-pattern içindeki pattern matching ile her zaman iyi uyuşmuyor. Bu kütüphanelerin tip tanımları labirent gibi ve çalışacakmış gibi görünen kod bazen beklendiği gibi davranmıyor. Runtime güvenliği ile exhaustiveness checking pattern matching pürüzsüz biçimde birleşebilse çok iyi olurdu
    • JavaScript’e gerçekten böyle bir özelliğin girmesi iyi bir şey mi, bundan ciddi biçimde şüpheliyim
      Promise, decorator’lar ve yeni pipe operatörünün hepsinde, uygulamanın gittiği yönün yanlış olduğunu hissediyorum
  • TypeScript geliştiricilerinden birinin, yeniden başlasalardı enum eklemeyeceklerini söylediğini hatırlıyorum. Çünkü enum, runtime kodu üreten tek özellik
    TypeScript runtime davranışını değiştirmez ve TypeScript’e özel {#if} benzeri bir şey de yoktur

    • Bu doğru. Bunun tek neden olup olmadığını bilmiyorum ama kesinlikle nedenlerden biriydi
      Yine de TypeScript’te “JavaScript + tip açıklamaları”nın ötesine geçen birkaç özellik var. namespace, constructor argümanlarında sınıf property’lerini tanımlama sözdizimi, eski deneysel decorator’lar ve derleme sırasında kaybolsa da JS fonksiyonlarına yalnızca tip açıklaması eklemekten fazlası gibi görünen this parametresi sözdizimi bunlardan bazıları
  • Daha iyi bir başlık, “TypeScript, reflection/runtime tipleri sağlasın” olurdu
    Şu an en iyi çözüm muhtemelen emitDecoratorMetadata. https://www.typescriptlang.org/tsconfig#emitDecoratorMetadata

  • Yazarın TypeScript'in tasarım hedefini yanlış anladığı görülüyor. Amaç, karmaşıklık içermeyen temiz JS çıktısı üretmek değil, TypeScript'in çalışma zamanı anlambiliminin JavaScript ile aynı kalmasını sağlamak.
    Talihsiz bir istisna olan enum dışında, TypeScript tür ek açıklamalarının kaldırılmasıyla JavaScript'e dönüşür. TypeScript etrafındaki ekosistem tamamen tür silmeye dayanır ve bu talep kabul edilirse ESBuild, Deno ve Bun'ın TS desteği neredeyse imkansız hale gelebilir. Çünkü her birinin tsc'nin tamamını kendi dillerinde yeniden uygulaması gerekir.
    Öte yandan OP'nin şikayet ettiği karmaşık kütüphaneler kullanıcı alanında uygulanmıştır, bu yüzden bu araçlarla uyumludur

    • Çalışma zamanı olmadan da statik olarak çalışma zamanı tür bilgisini dışa aktarmanın birçok yolu var. keyof, sınıf anahtarları listesine dönüştürülebilir ya da TS sınıfları ES6 sınıfları gibi anahtarları undefined ile başlatacak şekilde ayarlanabilir
      Şu anda TypeScript sınıfları açıkça tanımlanmamış tüm anahtarları kaldırıyor; bu yüzden yeni bir örnekte Object.keys() çağırırsanız hiçbir şey çıkmıyor. TS sınıflarını ES6 sınıfları gibi dönüştüren bir tsconfig.json seçeneği ya da ES6 sınıflarına TS içinde birlikte izin verilmesi bile kod üretimini çok daha kolay hale getirir.
      Ayrıca tstypeof Foo::bar gibi statik bir sözdizimi "string" olarak derlense harika olurdu. Temel düzeyde RTTI bile olsa, dağınık boilerplate TypeScript kodunun önemli bir kısmı anında ortadan kalkabilir
  • Bu yazıyı görmek sevindirici. 2018'de TypeScript'e başladım ve yaklaşık 2 yıl sonra bunun özünde tam bir çözüm olmadığına inanmaya başladım
    Haskell/C#/F# geçmişim var ama TS, güçlü bir tür sistemine sahip olsa da geliştirme sürecinin bazı bölümleri dışında bu dillerin sağladığı avantajların çoğunu vermiyor. Gerçek dünyayla uğraşırken pratikte C#'tan çok daha sınırlı. Derlemeden sonra doğrulama olmadan JS'ye düştüğünü bilmiyorsanız, statik tip iddia eden bir araçta imkansız olması gereken hatalardan kaçınmak için sızdıran soyutlamaların her zaman farkında olmanız gerekiyor

    • TypeScript'in amacı her zaman web'de çalışmaktı; C#'a göre dil düzeyinde bir üstünlük sağlamak değildi
      .NET geliştirmeniz gerekiyorsa C# kullanın, web geliştirmeniz gerekiyorsa TypeScript kullanın. C# nominal tiplidir ve oldukça iyi yenidenleştirilmiş generics'e sahiptir; TypeScript ise yapısal tiplidir ve soundness'tan ödün vererek karmaşık tür ilişkilerini ifade eden güçlü bir tür sistemi sunar.
      İkisini birleştiren bir dilin iyi olup olmayacağı şüpheli; iki dil farklı yönlerde iyi çalışıyor ama bu yönler birbiriyle pek uyumlu değil
  • Çalışma zamanı veri doğrulaması için https://zod.dev kullanmaktan tamamen memnun kaldım
    Ayrı nominal tipleri ayrıca tanımlamak zorunda kalmadan, akıcı bir API ile niyeti doğrudan yerinde ifade edebilmek oldukça hoşuma gitti

    • Nominal tiplerin başka kullanım alanları var
      Basit bir örnek olarak, bir etki alanında sayı 2 ile para tutarı 2'yi ayırt etmek için buna ihtiyaç duyarsınız