TypeScript പ്രൊഡക്ഷനിൽ എത്തുന്നതിന് മുമ്പ് തന്നെ വിവരക്കേടുകൾ നിറഞ്ഞ ബഗുകളെ (bugs) കണ്ടെത്തുന്നു. തെറ്റായ പ്രോപ്പർട്ടി പേരുകൾ (misspelled property), നിങ്ങൾ മറന്നുപോയ ആർഗ്യുമെന്റുകൾ (argument), തെറ്റായ രൂപത്തിൽ റിട്ടേൺ ചെയ്യുന്ന ബ്രാഞ്ചുകൾ (branch) എന്നിവയെക്കുറിച്ച് ഇത് നിങ്ങളെ താക്കീത് ചെയ്യുന്നു. നിങ്ങൾ അത് ശരിയാക്കുന്നു, ബിൽഡ് വിജയിക്കുന്നു, നിങ്ങൾ അത് ഷിപ്പ് ചെയ്യുന്നു. എന്നാൽ സ്റ്റാറ്റിക് ടൈപ്പുകൾക്ക് (static types) ഒരു പരിധിയുണ്ട്. കംപൈലർ ജോലി പൂർത്തിയാക്കിയാൽ, എല്ലാ അനോട്ടേഷനുകളും (annotations) നീക്കം ചെയ്യപ്പെടുന്നു. നിങ്ങളുടെ കോഡ് പ്രവർത്തിപ്പിക്കുന്ന JavaScript എൻജിന് നിങ്ങളുടെ ഇന്റർഫേസുകളെക്കുറിച്ചോ (interfaces), ബ്രാൻഡഡ് ടൈപ്പുകളെക്കുറിച്ചോ (branded types), അല്ലെങ്കിൽ നിങ്ങൾ ശ്രദ്ധാപൂർവ്വം നിർവചിച്ച സ്ട്രിംഗ് ലിറ്ററലുകളെക്കുറിച്ചോ (string literals) അറിയില്ല. അതിന് മൂല്യങ്ങളെക്കുറിച്ചും (values) ഭാഷയുടെ യഥാർത്ഥ നിയമങ്ങളെക്കുറിച്ചും മാത്രമേ അറിയൂ.
ബിൽഡ് വിജയിക്കുന്നു എന്നതിനർത്ഥം റൺടൈമിൽ (runtime) സുരക്ഷിതമാണ് എന്നല്ല. ടെസ്റ്റുകൾ പച്ച നിറത്തിൽ കാണപ്പെടുന്നു (tests green) എന്നതിനർത്ഥം ഉപയോക്താക്കൾക്ക് ഒരു സുസ്ഥിരമായ ആപ്ലിക്കേഷൻ ലഭിക്കുന്നു എന്നല്ല. നിങ്ങളുടെ മാനസിക മാതൃക (mental model) TypeScript പരിധിയിൽ അവസാനിക്കുന്നുവെങ്കിൽ, യഥാർത്ഥത്തിൽ ക്രാഷുകൾ (crashes) സംഭവിക്കുന്ന ഇടത്ത് നിങ്ങൾ കണ്ണടച്ച് പറക്കുകയാണ്.
കംപൈൽ-ടൈം മിരാജ് (The Compile-Time Mirage)
കംപൈലേഷൻ സമയത്ത് TypeScript-ന്റെ മുഴുവൻ ടൈപ്പ് സിസ്റ്റവും ഇല്ലാതാകുന്നു. ഏതെങ്കിലും പ്രോജക്റ്റിന്റെ കംപൈൽ ചെയ്ത JavaScript ഔട്ട്പുട്ട് പരിശോധിച്ചാൽ interface, type, അല്ലെങ്കിൽ ജനറിക് കൺസ്ട്രയിന്റുകൾ (generic constraints) എന്നിവയുടെ ഒരു അടയാളവും കാണില്ല. അവ ഡിസൈൻ സമയത്തെ നിർമ്മാണ ഘട്ടങ്ങൾ (scaffolding) മാത്രമാണ്. ബ്രൗസറോ Node.js പ്രോസസ്സോ പ്രവർത്തിപ്പിക്കുന്നത് പ്ലെയിൻ JavaScript ആണ്, അതിനാൽ നിങ്ങളുടെ ഫംഗ്ഷനുകളിലൂടെ ഒഴുകുന്ന മൂല്യങ്ങൾ നിങ്ങൾ രേഖപ്പെടുത്തിയ ടൈപ്പുകളുമായി പൊരുത്തപ്പെടുമെന്ന് ഉറപ്പില്ല.
സിസ്റ്റത്തിന്റെ അതിരുകളിൽ (edges) ഈ വിടവ് ഏറ്റവും കൂടുതൽ പ്രസക്തമാണ്. നെറ്റ്വർക്ക് റെസ്പോൺസുകൾ (network responses), ഉപയോക്തൃ ഇൻപുട്ടുകൾ (user input), തേർഡ് പാർട്ടി ലൈബ്രറികൾ എന്നിവ നിങ്ങളുടെ ടൈപ്പുകളെ ലംഘിക്കുന്ന മൂല്യങ്ങൾ നൽകിയേക്കാം. വിശ്വസിക്കാൻ കൊള്ളാത്ത ഒരു API വഴി തെറ്റായ ഡാറ്റ വന്നാൽ, strictEmail: string എന്ന് നിങ്ങൾ പ്രഖ്യാപിച്ച ഒരു വേരിയബിളിൽ റൺടൈമിൽ ഒരു നമ്പർ പോലും വരാം. സ്റ്റാറ്റിക് അനാലിസിസിന് (static analysis) ഒരിക്കലും കണ്ടെത്താൻ കഴിയാത്ത പരാജയങ്ങളിലേക്ക് ഈ രണ്ട് തലങ്ങളെയും (planes) തമ്മിൽ കൂട്ടിക്കലർത്തുന്നത് കാരണമാകും.
സംഖ്യകൾ നിങ്ങളെ വഞ്ചിക്കുമ്പോൾ
TypeScript ഒരു number കാണുന്നു. എന്നാൽ JavaScript എൻജിൻ കാണുന്നത് ഒരു IEEE 754 ഡബിൾ പ്രിസിഷൻ ഫ്ലോട്ട് (double-precision float) ആണ്. ഈ വ്യത്യാസം വലിയൊരു ദുരന്തമായി മാറുന്നതുവരെ അത് നിസ്സാരമായി തോന്നാം.
JavaScript ഓരോ നമ്പറിനും 64 ബിറ്റുകൾ അനുവദിക്കുന്നുണ്ടെങ്കിലും, അതിൽ 53 ബിറ്റുകൾ മാത്രമേ മാന്റിസ (mantissa) സംഭരിക്കാൻ ഉപയോഗിക്കുന്നുള്ളൂ. ഇത് 9,007,199,254,740,991 എന്ന സുരക്ഷിതമായ ഇന്റീജർ പരിധി (safe integer ceiling) സൃഷ്ടിക്കുന്നു. ഇതിനേക്കാൾ വലിയ ഏതൊരു സംഖ്യയും അടുത്ത ലഭ്യമായ മൂല്യത്തിലേക്ക് റൗണ്ട് (round) ചെയ്യപ്പെടും. പ്രായോഗികമായി പറഞ്ഞാൽ, നിങ്ങളുടെ ആപ്ലിക്കേഷനുള്ളിൽ രണ്ട് വ്യത്യസ്ത ഐഡന്റിഫയറുകൾ (identifiers) ഒരേ മൂല്യമായി മാറാൻ ഇത് കാരണമാകും.
Snowflake IDs-ഉം മറ്റ് വിതരണ രീതിയിലുള്ള (distributed) 64-ബിറ്റ് ഇന്റീജർ ഐഡന്റിഫയറുകളും പതിവായി ഈ പരിധി മറികടക്കുന്നു. ഉയർന്ന മൂല്യമുള്ള കറൻസി യൂണിറ്റുകൾ ട്രാക്ക് ചെയ്യുന്ന സാമ്പത്തിക സംവിധാനങ്ങളും ഇതിൽ അകപ്പെടാം. നിങ്ങളുടെ ബിസിനസ് ലോജിക് പ്രവർത്തിക്കുന്നതിന് മുമ്പ് തന്നെ അപകടം സംഭവിക്കാം: JSON.parse ഒരു പേലോഡിലെ (payload) സംഖ്യാ മൂല്യങ്ങളെ JavaScript നമ്പറുകളായി മാറ്റുമ്പോൾ, അവയുടെ കൃത്യത (precision) നിശബ്ദമായി നഷ്ടപ്പെടാം. നിങ്ങളുടെ ടൈപ്പ് ഡെഫനിഷൻ id: number എന്ന് വാഗ്ദാനം ചെയ്തേക്കാം, എന്നാൽ ആദ്യത്തെ ഫംഗ്ഷൻ കോളിന് മുമ്പ് തന്നെ റൺടൈം മൂല്യം കേടുപാടുകൾ സംഭവിച്ചതാകാം.
ഇതിനുള്ള പരിഹാരം ലളിതമാണ്, എന്നാൽ നിങ്ങളുടെ സ്റ്റാക്കിൽ (stack) കൃത്യമായ അച്ചടക്കം ആവശ്യമാണ്. നെറ്റ്വർക്ക് ട്രാൻസ്പോർട്ട് സമയത്ത് വലിയ ഐഡന്റിഫയറുകൾ സ്ട്രിംഗുകളായി (strings) സൂക്ഷിക്കുക. നിങ്ങളുടെ JSON സ്കീമുകളിലും API കോൺട്രാക്റ്റുകളിലും ഈ ഫീൽഡുകൾ നമ്പറുകളായല്ല, മറിച്ച് സ്ട്രിംഗുകളായി നിർവചിക്കുക. സുരക്ഷിത പരിധിക്ക് പുറത്തുള്ള മൂല്യങ്ങളിൽ നിങ്ങൾക്ക് ഗണിതക്രിയകൾ ചെയ്യേണ്ടി വന്നാൽ BigInt ഉപയോഗിക്കുക. എന്നാൽ ശ്രദ്ധിക്കുക: BigInt സാധാരണ JavaScript നമ്പറുകളുമായി നേരിട്ട് ഇടപഴകില്ല, കൂടാതെ JSON.stringify ഉപയോഗിക്കുമ്പോൾ BigInt-നെ സ്ട്രിംഗിലേക്ക് മാറ്റാതെ നേരിട്ട് ഉപയോഗിക്കാൻ കഴിയില്ല. ഐഡന്റിഫയറുകളെ ഡിഫോൾട്ട് ആയി ഒപാക് ടോക്കണുകളായി (opaque tokens) പരിഗണിക്കുക. യഥാർത്ഥത്തിൽ കണക്കുകൂട്ടലുകൾ ആവശ്യമായ ഒരു ഐസൊലേറ്റഡ് കാൽക്കുലേഷൻ മോഡ്യൂളിനുള്ളിൽ എത്തുമ്പോൾ മാത്രം അവയെ സംഖ്യാ രൂപത്തിലേക്ക് മാറ്റുക.
