1 पॉइंट द्वारा GN⁺ 2023-07-09 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • TypeScript में runtime type information emit करने की आवश्यकता का तर्क दिया गया है, और इस समस्या को बायपास करने वाले Type Mapping, Code Generation / External Tool, तथा Adapter प्रोजेक्ट्स की एक सूची संकलित की गई है
  • मुख्य समस्या यह है कि reflective type system के बिना serialization और validation को संभालने पर अंतहीन boilerplate या schema file-आधारित bespoke code generation की ज़रूरत पड़ती है
  • workaround के रूप में io-ts, zod आदि पेश किए जाते हैं, लेकिन types को हर library के तरीके से फिर से declare करना पड़ता है और libraries TypeScript की सभी type features को support नहीं कर पातीं, जिससे असुविधा होती है
  • यह माना गया है कि TypeScript का type erasure इस लिहाज़ से फ़ायदेमंद है कि JavaScript projects, TypeScript की जानकारी के बिना emit किए गए JavaScript का उपयोग कर सकते हैं, फिर भी यह तर्क दिया गया है कि code से अलग lookup table के रूप में type information emit की जा सकती है
  • decorators से इसे हल न करने का अनुरोध किया गया है, और interface के उपयोग तथा external library types के support के लिए typescript.generateRuntimeType<T>() जैसी compiler-recognized higher-order function, F# Type Providers, और C# Source Generators जैसे approaches सुझाए गए हैं
  • संबंधित मौजूदा चर्चाओं में 8 साल पुराना GitHub issue जोड़ा गया है, और अनुरोध किया गया है कि अगर किसी project ने यही समस्या झेली है तो approach की संख्या की परवाह किए बिना सूची में जोड़ने के लिए PR भेजें

1 टिप्पणियां

 
GN⁺ 2023-07-09
Hacker News टिप्पणियाँ
  • यह समझने के लिए कि माँगा क्या जा रहा है, मुझे समस्या विवरण लगभग 4 बार पढ़ना पड़ा, और यह वही तरह का मामला है जो दिखाता है कि संक्षिप्त लेखन क्यों महत्वपूर्ण है
    असली मांग runtime type safety की लगती है, लेकिन TypeScript लंबे समय से यह रेखा खींचता आया है कि वह JavaScript का replacement/augmented runtime नहीं बनेगा, इसलिए इसकी संभावना कम लगती है। TypeScript की भूमिका JS में compile होकर हट जाने की है, और उसके बाद V8 आदि में जो होता है वह उसके दायरे से बाहर है।
    “TypeScript को runtime type information emit करनी चाहिए” जैसी मांग, मौजूदा TypeScript से काफ़ी अलग एक नया product मांगने के ज़्यादा करीब है

    • यह runtime type safety की सीधी मांग से ज़्यादा, compile time पर type reflection करके values generate करने और उस जानकारी को runtime में इस्तेमाल करने की मांग के करीब है
      उदाहरण के लिए, कोई generic validate function हो जो किसी भी interface और object को लेकर validation कर सके। Compile-time reflection से type-specific JS validation code generate करना, या runtime पर T को argument के रूप में देकर compare करना संभव हो सकता है, लेकिन मौजूदा TypeScript philosophy में यह कठिन लगता है
    • सिर्फ शीर्षक देखकर ही समझ गया कि यह बहुत समय से चाही गई feature है, और यह ज़्यादा official तथा बेहतर supported https://github.com/rbuckton/reflect-metadata जैसी चीज़ की मांग के करीब है
      TypeScript compilation के दौरान बहुत-सी type information जानता है, लेकिन compile खत्म होने पर उसे फेंक देता है। इस जानकारी को file में emit किया जा सकता है या Reflect पर metadata के रूप में छोड़ा जा सकता है, फिर भी इसे त्याग देना खासकर JavaScript की “everything is an object” प्रकृति को देखते हुए एक अफ़सोसजनक सीमा है।
      भले ही पूरी TS type safety न मिले, getter/setter या ES2015 Proxy से कुछ checks जोड़े जा सकते हैं, और अगर type information runtime में बची रहे तो executable metadata के रूप में कई दिलचस्प संभावनाएँ खुलती हैं
    • यह कहना सही नहीं कि TypeScript compiler है इसलिए यह असंभव है। Type information को JS object के रूप में output करके runtime में query करने वाली reflection library का support दिया जा सकता है
      TS enum पहले से JS object के रूप में output होता है, इसलिए runtime query संभव है, लेकिन string literal union type के साथ ऐसा नहीं है। TypeScript type guard functions को भी support करता है, इसलिए type system की जानकारी से ऐसी functions auto-generate करना भी बहुत कठिन नहीं लगता
    • सरसरी तौर पर देखने पर भी मांग साफ़ थी। बात यह है कि TypeScript type erasure के दौरान मिली type information को generated JavaScript के साथ एक अतिरिक्त channel में emit करे
      इसे PDB file जैसी उपमा से समझा जा सकता है। यह वह जानकारी है जो TypeScript के पास पहले से होती है और बाद में फेंक दी जाती है, इसलिए इसके लिए पूरी तरह नया product ज़रूरी नहीं है
    • README के शीर्ष पर “7 साल पुराना GitHub issue” लिंक है, और वहाँ समस्या को और सीधे ढंग से समझाया गया है
      https://github.com/microsoft/TypeScript/issues/3628
  • TypeScript PM के नज़रिए से इस इच्छा को समझा जा सकता है। Data validation में अक्सर runtime type checking की ज़रूरत पड़ती है, और उस कमी को भरने के लिए कई libraries भी हैं
    लेकिन यह तथ्य कि अलग-अलग design decisions वाली इतनी libraries मौजूद हैं, खुद इस बात का संकेत है कि यह कोई ऐसा solved problem नहीं है जिसका एक स्पष्ट सही उत्तर हो। TypeScript के शुरुआती design के समय भी यह बात ज्ञात थी, और लगता है कि यह सिद्धांत काफ़ी अच्छी तरह कायम रहा है।
    इसके बजाय TypeScript इतना शक्तिशाली हो गया है कि runtime type checking libraries जो वास्तव में करती हैं, उसे types में काफ़ी सटीक रूप से व्यक्त कर सके, और users APIs के ज़रिए types से runtime validation logic बना सकते हैं। यह एक उचित स्तर की flexibility लगता है

    • मैंने programming शुरू किए ज़्यादा समय नहीं हुआ, लेकिन मैं सोचता हूँ कि TypeScript अधिक परिष्कृत user-defined data types क्यों नहीं बना सकता
      उदाहरण के लिए, किसी निश्चित range के भीतर number या postal code pattern को satisfy करने वाली string को type के रूप में define किया जाए, और compiler validity जाँचने के लिए सामान्य functions की तरह लिखे गए validation functions का उपयोग करे। मैं सोचता हूँ कि ऐसी feature का न होना क्या अनावश्यक जटिलता से बचने का design decision है, या performance जैसी तकनीकी सीमाओं की वजह से है
    • अगर TypeScript compiler में आधिकारिक preprocessor plugins हों, तो यह मददगार हो सकता है
      अभी भी जिन्हें ज़रूरत है वे tsc को देने से पहले type information से runtime objects generate करने वाला preprocessor बना सकते हैं, लेकिन प्रयास बिखरे हुए हैं। अगर कोई आधिकारिक pluggable preprocessor और ecosystem हो, तो अच्छा समाधान निकल सकता है
    • अगर Microsoft TypeScript plugin या top-level wrapper के रूप में MacroScript host करे, तो यह समस्या हल हो सकती है
      बस शुरुआत मिल जाए तो community maintenance में मदद करेगी, और client generation से लेकर runtime type assertions तक कई code generation needs हल हो सकती हैं
    • compile के बाद type information को Class objects में छोड़ने वाले दूसरे proposal के बारे में लोग क्या सोचते हैं?
  • इसे न करने की एक वजह है। TypeScript, JavaScript के ऊपर किसी runtime जैसी चीज़ बन जाएगा, और JS में compile होने वाली एक नई भाषा बनकर रह जाएगा
    अभी TypeScript, type annotations लगे JavaScript के काफ़ी क़रीब है। JS में compile होने वाली भाषाएँ पहले से बहुत हैं, तो उनमें से कोई एक इस्तेमाल की जा सकती है। जिन्हें runtime types वाला TypeScript चाहिए, वे शायद JavaScript की तुलना में Java/OOP style code लिखना चाहते हैं, लेकिन JavaScript एक dynamic type language है, और यही उसकी एक खूबी भी है

    • ज़रूरी नहीं। अगर generateTypeInfo!() जैसा कोई macro Foo type को encode करने वाले JS object में expand हो, तो वह अब भी पढ़ने योग्य JavaScript में compile होगा
      लेकिन यह macro उस गुण को तोड़ देता है कि “TS = type annotations वाला JS है और compile करने के लिए बस annotations हटाने होते हैं।” क्योंकि इसमें Foo के structural type की वास्तव में गणना करनी पड़ती है।
      और TypeScript types structural होते हैं, इसलिए runtime पर object structure की जाँच करके कुछ हद तक type जाना जा सकता है, लेकिन अगर erased nominal information या type name चाहिए हों, जैसे यह जाँचना कि कोई string union में है या नहीं, तो TypeScript type system की Turing-completeness और implicit structural conversion की वजह से यह जल्दी ही कठिन समस्या बन जाती है
    • दोनों चीज़ें साथ हो सकती हैं। Lisp की homoiconicity जैसी दुनिया की कल्पना की जा सकती है, जहाँ code और data काफ़ी क़रीब हों
      गंभीरता से कहें तो, runtime के बिना भी अगर types को data के रूप में expose किया जाए, तो reflection मिल सकता है। इतने सारे developers ने इसकी नकल करने की कोशिश की है कि इसे न करना उल्टा मूर्खता जैसा लगता है
    • वह तर्क मुझे ठीक से समझ नहीं आता। TypeScript पहले से ही JS में compile होने वाली एक नई superset language है
      runtime types, compile-time type system और data validation type system को अलग-अलग duplicate बनाए रखने की समस्या हल करते हैं, और इसका OOP से सीधा संबंध नहीं दिखता। इस समस्या के workaround libraries में जिस io-ts को लोग पसंद करते हैं, वह भी functional programming पर काफ़ी निर्भर है
    • काफ़ी बड़े projects में dynamic type language अच्छी नहीं होती, और NaN जैसे अनपेक्षित values पर बार-बार ठोकर खाना एक उलझी हुई आपदा जैसा है
      मैंने जिन workflows में देखा है, उनमें TypeScript पहले से JS में compile होने वाली भाषा है, तो बेहतर यही है कि उसके इस फ़ायदे का पूरा इस्तेमाल किया जाए
    • TypeScript सिर्फ type annotations लगा हुआ JavaScript नहीं है। वह उसका एक mode हो सकता है, लेकिन उसमें पुराने JS structures emit करने की क्षमता भी है, इसलिए output मूल TS code से बिल्कुल अलग दिख सकता है
      यह type annotations + Babel के ज़्यादा क़रीब है, और इसमें एक बेहद उपयोगी feature और जोड़ना अच्छा विचार होगा। JSON.parse की गई string को typed structure में सुरक्षित रूप से बदल न पाना अजीब है, जबकि दूसरी भाषाओं में यह आम तौर पर संभव है
  • नीचे की बातों से पहले, यह बहस के लायक एक वैध विषय है और मुझे नहीं लगता कि इसका कोई एक वस्तुनिष्ठ सही जवाब है
    TypeScript, Enum द्वारा object export करने वाले अपवाद को छोड़ दें तो, JavaScript के ऊपर एक optional layer है, और TS code types हटाने पर JS बन जाता है। अगर इस सिद्धांत से बहुत दूर न जाएँ, तो असली माँग type से serializer/validator बनाने वाली library जैसी लगती है। ऐसी libraries पहले से बहुत हैं, इसलिए यह माँग आख़िरकार उनमें से किसी एक को आधिकारिक standard विकल्प बनाने जैसी दिखती है।
    निजी तौर पर मैं नहीं चाहता कि TypeScript की core language में runtime reflection आए। runtime पर सिर्फ JavaScript हो, और source map न होने पर भी output JS पढ़ने योग्य और debug करने लायक रहे—मैं इस बात को काफ़ी महत्व देता हूँ

    • Enum के अलावा भी runtime code emit करने वाले अपवाद हैं, और उनमें से ज़्यादातर को भी गलती ही माना जाता है। उदाहरण के लिए module और namespace runtime structures थे
      हालाँकि पिछले कुछ वर्षों में उनका इस्तेमाल मुख्यतः TypeScript के अंदर ही हुआ, और TypeScript भी हाल के समय में उनसे दूर जा रहा है। एक और काफ़ी लोकप्रिय अपवाद parameter properties हैं, जो constructor parameters से class member types define करने का syntax है, और क्योंकि यह दोहराया हुआ boilerplate कम करता है, शायद इसलिए इस पर कम विवाद हुआ
    • “TS code बिना transformation के JS बन जाता है” यह बात तभी कही जा सकती है जब पूरे language design और type notation को उस नज़र से देखा जाए
  • TypeScript देवताओं से विनती करने के बजाय, शायद JavaScript पक्ष से सौदा करके type checking को JS में लाना बेहतर होगा
    अगर runtime types चाहिए, तो type guards का इस्तेमाल करें, और अगर यह बार-बार चाहिए, तो io-ts या zod से types को validator/codec/schema के रूप में लिखें। जब तक JavaScript में इस पर कोई सहमति वाला तरीका नहीं आता, मुझे नहीं लगता कि TS spec, type checker और community को runtime validation का बोझ उठाना चाहिए

    • यह परफ़ेक्ट नहीं है, लेकिन zod से schema और validators लिखकर वहीं से types derive करने वाला तरीका मुझे काफ़ी पसंद है। अच्छा यह है कि validation, type changes के साथ-साथ evolve होती रहती है
      कुछ लोगों को लगता है कि ऐसी सुविधा language में होनी चाहिए, लेकिन हर library में कई विवादास्पद design choices होती हैं, इसलिए project की ज़रूरत के हिसाब से implementation चुनना शायद बेहतर है।
      लेकिन zod runtime validation और schema-based type derivation जैसे pattern, ts-pattern की pattern matching के साथ हमेशा अच्छी तरह फिट नहीं बैठते। इन libraries की type definitions किसी भूलभुलैया जैसी हैं, और कभी-कभी जो code चलना चाहिए लगता है, वह उम्मीद के मुताबिक काम नहीं करता। अगर runtime safety और exhaustiveness-checked pattern matching सहज रूप से जुड़ जाएँ, तो वह बहुत अच्छा होगा
    • JavaScript में सचमुच ऐसी सुविधा आना अच्छा होगा या नहीं, इस पर मुझे बड़ा संदेह है
      Promise, decorators, और नया pipe operator—तीनों के implementation direction मुझे ग़लत लगे हैं
  • मुझे याद है कि TypeScript developers में से एक ने कहा था कि अगर फिर से शुरू करना पड़े तो वह enum नहीं जोड़ते। वजह यह थी कि enum ही वह एकमात्र feature है जो runtime code emit करता है
    TypeScript runtime behavior नहीं बदलता, और उसमें TypeScript-विशेष {#if} जैसी कोई चीज़ भी नहीं है

    • यह बात सही है। पता नहीं वही एकमात्र वजह थी या नहीं, लेकिन यह निश्चित रूप से एक वजह थी
      फिर भी TypeScript में कुछ features ऐसे हैं जो “JavaScript + type annotations” से आगे जाते हैं। जैसे namespace, constructor arguments में class properties define करने का syntax, पुराने experimental decorators, और this parameter syntax, जो compile होने पर गायब हो जाता है लेकिन JS functions पर सिर्फ type annotations लगाने से ज़्यादा जैसा लगता है
  • इससे बेहतर शीर्षक शायद “TypeScript, reflection/runtime types दे” जैसा होगा
    अभी सबसे अच्छा समाधान शायद emitDecoratorMetadata लगता है। https://www.typescriptlang.org/tsconfig#emitDecoratorMetadata

  • लेखक को शायद TypeScript के design goals की गलतफहमी है। लक्ष्य बिना complexता वाला साफ़ JS output बनाना नहीं, बल्कि TypeScript की runtime semantics को JavaScript के समान बनाए रखना है
    अफसोसनाक अपवाद enum को छोड़ दें तो TypeScript सिर्फ type annotations हटाने पर JavaScript बन जाता है। TypeScript का पूरा ecosystem पूर्ण type erasure पर निर्भर करता है, और अगर यह मांग मान ली गई तो ESBuild, Deno, और Bun का TS support लगभग असंभव हो सकता है। क्योंकि फिर हर एक को पूरे tsc को अपनी-अपनी भाषा में दोबारा implement करना पड़ेगा।
    दूसरी ओर, OP जिन complex libraries की शिकायत कर रहा है, वे user space में implement की गई हैं, इसलिए ऐसे tools के साथ compatible हैं

    • runtime के बिना भी statically runtime type information export करने के कई तरीके हैं। keyof को class key list में बदला जा सकता है, या TS classes को ES6 classes की तरह keys को undefined से initialize करने दिया जा सकता है
      अभी TypeScript classes सभी ऐसी keys हटा देती हैं जो explicitly define नहीं की गई हैं, इसलिए नए instance पर Object.keys() call करने पर कुछ भी नहीं निकलता। सिर्फ tsconfig.json option के जरिए TS classes को ES6 classes की तरह transform कर दिया जाए, या ES6 classes को TS के अंदर साथ में allow कर दिया जाए, तो code generation बहुत आसान हो जाएगा।
      साथ ही, अगर tstypeof Foo::bar जैसी static syntax "string" में compile हो जाए, तो वह शानदार होगा। सिर्फ basic RTTI से भी काफी गंदा boilerplate TypeScript code तुरंत बहुत कम हो सकता है
  • यह लेख अच्छा लगा। मैंने 2018 में TypeScript शुरू किया था और करीब 2 साल बाद मुझे लगने लगा कि यह मूलतः पूरी तरह का समाधान नहीं है
    मैं Haskell/C#/F# से आया हूँ, और TS में powerful type system होने के बावजूद, development के कुछ हिस्सों को छोड़कर उन भाषाओं वाले फायदे काफी हद तक नहीं मिलते। real world को handle करते समय यह practical रूप से C# से कहीं ज़्यादा सीमित है। अगर आपको यह बात न पता हो कि compile होने के बाद यह बिना checks के JS बन जाता है, तो leaky abstraction को लगातार ध्यान में रखना पड़ता है ताकि ऐसे bugs से बचा जा सके जो static typing का दावा करने वाले tool में संभव नहीं होने चाहिए

    • TypeScript का उद्देश्य हमेशा web पर चलना था, C# पर भाषाई बढ़त देना नहीं
      अगर .NET develop करना है तो C# इस्तेमाल करें, और web develop करना है तो TypeScript। C# nominal typing वाला है और उसमें काफ़ी अच्छी reified generics हैं, जबकि TypeScript structural typing वाला है और soundness छोड़ने के बदले complex type relationships को व्यक्त करने वाला शक्तिशाली type system देता है।
      दोनों को मिलाकर बनी भाषा अच्छी होगी या नहीं, इस पर संदेह है; दोनों भाषाएँ अपनी-अपनी अलग दिशा में अच्छी तरह काम करती हैं, लेकिन वे दिशाएँ एक-दूसरे से खास मेल नहीं खातीं
  • runtime data validation के लिए https://zod.dev इस्तेमाल करके मैं पूरी तरह संतुष्ट रहा हूँ
    यह काफी अच्छा लगा कि अलग से nominal types define किए बिना, fluent API के साथ वहीं पर intent व्यक्त किया जा सकता है

    • nominal types का उपयोग अलग है
      एक आसान उदाहरण के तौर पर, domain में संख्या 2 और मुद्रा राशि 2 के बीच फर्क करने के लिए इसकी ज़रूरत होती है