അടിസ്ഥാന ടൈപ്പിംഗിനപ്പുറം, കണ്ടീഷണൽ ടൈപ്പുകൾ, ടെംപ്ലേറ്റ് ലിറ്ററലുകൾ, സ്ട്രിംഗ് മാനിപ്പുലേഷൻ എന്നിവയിൽ പ്രാവീണ്യം നേടി ശക്തവും ടൈപ്പ്-സേഫുമായ API-കൾ നിർമ്മിക്കുക. ആഗോള ഡെവലപ്പർമാർക്കുള്ള ഒരു സമഗ്ര ഗൈഡ്.
ടൈപ്പ്സ്ക്രിപ്റ്റിന്റെ പൂർണ്ണ ശേഷി തുറക്കുന്നു: കണ്ടീഷണൽ ടൈപ്പുകൾ, ടെംപ്ലേറ്റ് ലിറ്ററലുകൾ, നൂതന സ്ട്രിംഗ് മാനിപ്പുലേഷൻ എന്നിവയിലേക്കുള്ള ഒരു ആഴത്തിലുള്ള പഠനം
ആധുനിക സോഫ്റ്റ്വെയർ വികസനത്തിന്റെ ലോകത്ത്, ജാവാസ്ക്രിപ്റ്റിനുള്ള ഒരു ലളിതമായ ടൈപ്പ്-ചെക്കർ എന്ന പ്രാരംഭ റോളിൽ നിന്ന് ടൈപ്പ്സ്ക്രിപ്റ്റ് ഏറെ മുന്നോട്ട് പോയിരിക്കുന്നു. ടൈപ്പ്-ലെവൽ പ്രോഗ്രാമിംഗ് എന്ന് വിശേഷിപ്പിക്കാവുന്ന ഒന്നിനുള്ള ഒരു സങ്കീർണ്ണ ഉപകരണമായി ഇത് മാറിയിരിക്കുന്നു. ഈ മാതൃക ഡെവലപ്പർമാരെ ടൈപ്പുകളിൽ തന്നെ പ്രവർത്തിക്കുന്ന കോഡ് എഴുതാൻ അനുവദിക്കുന്നു, ഇത് ഡൈനാമിക്, സ്വയം-ഡോക്യുമെന്റ് ചെയ്യുന്ന, അതിശയകരമാംവിധം സുരക്ഷിതമായ API-കൾ സൃഷ്ടിക്കുന്നു. ഈ വിപ്ലവത്തിന്റെ ഹൃദയഭാഗത്ത് മൂന്ന് ശക്തമായ ഫീച്ചറുകൾ ഒരുമിച്ച് പ്രവർത്തിക്കുന്നു: കണ്ടീഷണൽ ടൈപ്പുകൾ, ടെംപ്ലേറ്റ് ലിറ്ററൽ ടൈപ്പുകൾ, കൂടാതെ ഒരു കൂട്ടം ഇൻട്രിൻസിക് സ്ട്രിംഗ് മാനിപ്പുലേഷൻ ടൈപ്പുകളും.
തങ്ങളുടെ ടൈപ്പ്സ്ക്രിപ്റ്റ് കഴിവുകൾ ഉയർത്താൻ ആഗ്രഹിക്കുന്ന ലോകമെമ്പാടുമുള്ള ഡെവലപ്പർമാർക്ക്, ഈ ആശയങ്ങൾ മനസ്സിലാക്കുന്നത് ഇനി ഒരു ആഡംബരമല്ല - സ്കെയിലബിളും പരിപാലിക്കാൻ കഴിയുന്നതുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിന് ഇത് ഒരു ആവശ്യകതയാണ്. ഈ ഗൈഡ് നിങ്ങളെ അടിസ്ഥാന തത്വങ്ങളിൽ നിന്ന് ആരംഭിച്ച്, അവയുടെ സംയോജിത ശക്തി പ്രകടമാക്കുന്ന സങ്കീർണ്ണവും യഥാർത്ഥ ലോക പാറ്റേണുകളിലേക്ക് കൊണ്ടുപോകും. നിങ്ങൾ ഒരു ഡിസൈൻ സിസ്റ്റം, ഒരു ടൈപ്പ്-സേഫ് API ക്ലയിന്റ്, അല്ലെങ്കിൽ ഒരു സങ്കീർണ്ണമായ ഡാറ്റാ-ഹാൻഡ്ലിംഗ് ലൈബ്രറി നിർമ്മിക്കുകയാണെങ്കിലും, ഈ ഫീച്ചറുകളിൽ പ്രാവീണ്യം നേടുന്നത് നിങ്ങൾ ടൈപ്പ്സ്ക്രിപ്റ്റ് എഴുതുന്ന രീതിയെ അടിസ്ഥാനപരമായി മാറ്റും.
അടിത്തറ: കണ്ടീഷണൽ ടൈപ്പുകൾ (The `extends` Ternary)
ഒരു കണ്ടീഷണൽ ടൈപ്പ്, ഒരു ടൈപ്പ് റിലേഷൻഷിപ്പ് പരിശോധനയെ അടിസ്ഥാനമാക്കി സാധ്യമായ രണ്ട് ടൈപ്പുകളിൽ ഒന്ന് തിരഞ്ഞെടുക്കാൻ നിങ്ങളെ അനുവദിക്കുന്നു. ജാവാസ്ക്രിപ്റ്റിന്റെ ടെർനറി ഓപ്പറേറ്ററുമായി (condition ? valueIfTrue : valueIfFalse) നിങ്ങൾക്ക് പരിചയമുണ്ടെങ്കിൽ, ഇതിന്റെ സിന്റാക്സ് വളരെ എളുപ്പത്തിൽ മനസ്സിലാകും:
type Result = SomeType extends OtherType ? TrueType : FalseType;
ഇവിടെ, extends എന്ന കീവേഡ് നമ്മുടെ കണ്ടീഷനായി പ്രവർത്തിക്കുന്നു. SomeType എന്ന ടൈപ്പിനെ OtherType എന്നതിലേക്ക് അസൈൻ ചെയ്യാൻ കഴിയുമോ എന്ന് ഇത് പരിശോധിക്കുന്നു. ഒരു ലളിതമായ ഉദാഹരണത്തിലൂടെ നമുക്ക് ഇത് വിശദീകരിക്കാം.
അടിസ്ഥാന ഉദാഹരണം: ഒരു ടൈപ്പ് പരിശോധിക്കുന്നു
നൽകിയിരിക്കുന്ന ഒരു ടൈപ്പ് T ഒരു സ്ട്രിംഗ് ആണെങ്കിൽ true ആയും അല്ലെങ്കിൽ false ആയും റിസോൾവ് ചെയ്യുന്ന ഒരു ടൈപ്പ് ഉണ്ടാക്കാൻ നമ്മൾ ആഗ്രഹിക്കുന്നു എന്ന് കരുതുക.
type IsString
നമുക്ക് ഈ ടൈപ്പ് ഇങ്ങനെ ഉപയോഗിക്കാം:
type A = IsString<"hello">; // type A is true
type B = IsString<123>; // type B is false
ഇതാണ് അടിസ്ഥാനപരമായ നിർമ്മാണ ഘടകം. എന്നാൽ കണ്ടീഷണൽ ടൈപ്പുകളുടെ യഥാർത്ഥ ശക്തി infer എന്ന കീവേഡുമായി സംയോജിപ്പിക്കുമ്പോൾ പുറത്തുവരുന്നു.
`infer`-ന്റെ ശക്തി: ഉള്ളിൽ നിന്ന് ടൈപ്പുകൾ വേർതിരിച്ചെടുക്കൽ
infer എന്ന കീവേഡ് ഒരു ഗെയിം-ചേഞ്ചറാണ്. ഇത് extends ക്ലോസിനുള്ളിൽ ഒരു പുതിയ ജെനറിക് ടൈപ്പ് വേരിയബിൾ പ്രഖ്യാപിക്കാൻ നിങ്ങളെ അനുവദിക്കുന്നു, അതുവഴി നിങ്ങൾ പരിശോധിക്കുന്ന ടൈപ്പിന്റെ ഒരു ഭാഗം ഫലപ്രദമായി പിടിച്ചെടുക്കാൻ സാധിക്കുന്നു. പാറ്റേൺ മാച്ചിംഗിലൂടെ അതിന്റെ മൂല്യം ലഭിക്കുന്ന ഒരു ടൈപ്പ്-ലെവൽ വേരിയബിൾ ഡിക്ലറേഷനായി ഇതിനെ കരുതുക.
ഒരു Promise-നുള്ളിൽ അടങ്ങിയിരിക്കുന്ന ടൈപ്പിനെ പുറത്തെടുക്കുന്നത് ഇതിനൊരു ക്ലാസിക് ഉദാഹരണമാണ്.
type UnwrapPromise
നമുക്ക് ഇത് വിശകലനം ചെയ്യാം:
T extends Promise: ഇത്TഒരുPromiseആണോ എന്ന് പരിശോധിക്കുന്നു. അങ്ങനെയെങ്കിൽ, ടൈപ്പ്സ്ക്രിപ്റ്റ് അതിന്റെ ഘടനയുമായി പൊരുത്തപ്പെടുത്താൻ ശ്രമിക്കുന്നു.infer U: പൊരുത്തപ്പെടുത്തൽ വിജയകരമാണെങ്കിൽ, ടൈപ്പ്സ്ക്രിപ്റ്റ്Promiseറിസോൾവ് ചെയ്യുന്ന ടൈപ്പ് പിടിച്ചെടുത്ത്Uഎന്ന് പേരുള്ള ഒരു പുതിയ ടൈപ്പ് വേരിയബിളിലേക്ക് ഇടുന്നു.? U : T: കണ്ടീഷൻ ശരിയാണെങ്കിൽ (TഒരുPromiseആയിരുന്നുവെങ്കിൽ), ഫലമായുണ്ടാകുന്ന ടൈപ്പ്Uആയിരിക്കും (പുറത്തെടുത്ത ടൈപ്പ്). അല്ലാത്തപക്ഷം, ഫലമായുണ്ടാകുന്ന ടൈപ്പ് യഥാർത്ഥ ടൈപ്പായTതന്നെയായിരിക്കും.
ഉപയോഗം:
type User = { id: number; name: string; };
type UserPromise = Promise
type UnwrappedUser = UnwrapPromise
type UnwrappedNumber = UnwrapPromise
ഈ പാറ്റേൺ വളരെ സാധാരണമായതിനാൽ ടൈപ്പ്സ്ക്രിപ്റ്റ് ReturnType പോലുള്ള ബിൽറ്റ്-ഇൻ യൂട്ടിലിറ്റി ടൈപ്പുകൾ ഉൾപ്പെടുത്തിയിട്ടുണ്ട്, ഇത് ഒരു ഫംഗ്ഷന്റെ റിട്ടേൺ ടൈപ്പ് വേർതിരിച്ചെടുക്കാൻ ഇതേ തത്വം ഉപയോഗിച്ച് നടപ്പിലാക്കുന്നു.
ഡിസ്ട്രിബ്യൂട്ടീവ് കണ്ടീഷണൽ ടൈപ്പുകൾ: യൂണിയനുകളുമായി പ്രവർത്തിക്കുന്നു
കണ്ടീഷണൽ ടൈപ്പുകളുടെ കൗതുകകരവും നിർണ്ണായകവുമായ ഒരു സ്വഭാവം, പരിശോധിക്കുന്ന ടൈപ്പ് ഒരു "നേക്കഡ്" ജെനറിക് ടൈപ്പ് പാരാമീറ്റർ ആകുമ്പോൾ അവ ഡിസ്ട്രിബ്യൂട്ടീവ് ആയി മാറുന്നു എന്നതാണ്. ഇതിനർത്ഥം നിങ്ങൾ അതിലേക്ക് ഒരു യൂണിയൻ ടൈപ്പ് പാസ് ചെയ്യുകയാണെങ്കിൽ, കണ്ടീഷണൽ ആ യൂണിയനിലെ ഓരോ അംഗത്തിനും தனித்தனியாக പ്രയോഗിക്കപ്പെടുകയും ഫലങ്ങൾ ഒരു പുതിയ യൂണിയനിലേക്ക് തിരികെ ശേഖരിക്കുകയും ചെയ്യും.
ഒരു ടൈപ്പിനെ ആ ടൈപ്പിന്റെ ഒരു അറേ ആക്കി മാറ്റുന്ന ഒരു ടൈപ്പ് പരിഗണിക്കുക:
type ToArray
നമ്മൾ ToArray-യിലേക്ക് ഒരു യൂണിയൻ ടൈപ്പ് പാസ് ചെയ്താൽ:
type StrOrNumArray = ToArray
ഫലം (string | number)[] അല്ല. T ഒരു നേക്കഡ് ടൈപ്പ് പാരാമീറ്റർ ആയതിനാൽ, കണ്ടീഷൻ വിതരണം ചെയ്യപ്പെടുന്നു:
ToArrayഎന്നത്string[]ആയി മാറുന്നുToArrayഎന്നത്number[]ആയി മാറുന്നു
അന്തിമ ഫലം ഈ വ്യക്തിഗത ഫലങ്ങളുടെ യൂണിയനാണ്: string[] | number[].
യൂണിയനുകൾ ഫിൽട്ടർ ചെയ്യുന്നതിന് ഈ ഡിസ്ട്രിബ്യൂട്ടീവ് സ്വഭാവം അങ്ങേയറ്റം ഉപയോഗപ്രദമാണ്. ഉദാഹരണത്തിന്, ബിൽറ്റ്-ഇൻ Extract യൂട്ടിലിറ്റി ടൈപ്പ്, യൂണിയൻ T-യിൽ നിന്ന് U-വിലേക്ക് അസൈൻ ചെയ്യാവുന്ന അംഗങ്ങളെ തിരഞ്ഞെടുക്കാൻ ഇത് ഉപയോഗിക്കുന്നു.
ഈ ഡിസ്ട്രിബ്യൂട്ടീവ് സ്വഭാവം തടയണമെങ്കിൽ, extends ക്ലോസിന്റെ ഇരുവശത്തും ടൈപ്പ് പാരാമീറ്ററിനെ ഒരു ടപ്പിളിൽ പൊതിയാവുന്നതാണ്:
type ToArrayNonDistributive
type StrOrNumArrayUnified = ToArrayNonDistributive
ഈ ഉറച്ച അടിത്തറയോടെ, നമുക്ക് എങ്ങനെ ഡൈനാമിക് സ്ട്രിംഗ് ടൈപ്പുകൾ നിർമ്മിക്കാമെന്ന് പര്യവേക്ഷണം ചെയ്യാം.
ടൈപ്പ് ലെവലിൽ ഡൈനാമിക് സ്ട്രിംഗുകൾ നിർമ്മിക്കൽ: ടെംപ്ലേറ്റ് ലിറ്ററൽ ടൈപ്പുകൾ
ടൈപ്പ്സ്ക്രിപ്റ്റ് 4.1-ൽ അവതരിപ്പിച്ച ടെംപ്ലേറ്റ് ലിറ്ററൽ ടൈപ്പുകൾ, ജാവാസ്ക്രിപ്റ്റിന്റെ ടെംപ്ലേറ്റ് ലിറ്ററൽ സ്ട്രിംഗുകൾ പോലെയുള്ള ടൈപ്പുകൾ നിർവചിക്കാൻ നിങ്ങളെ അനുവദിക്കുന്നു. നിലവിലുള്ള സ്ട്രിംഗ് ലിറ്ററൽ ടൈപ്പുകളിൽ നിന്ന് പുതിയവ കൂട്ടിച്ചേർക്കാനും സംയോജിപ്പിക്കാനും നിർമ്മിക്കാനും ഇത് നിങ്ങളെ പ്രാപ്തരാക്കുന്നു.
സിന്റാക്സ് നിങ്ങൾ പ്രതീക്ഷിക്കുന്നത് പോലെ തന്നെയാണ്:
type World = "World";
type Greeting = `Hello, ${World}!`; // type Greeting is "Hello, World!"
ഇത് ലളിതമായി തോന്നാമെങ്കിലും, യൂണിയനുകളും ജെനറിക്സുമായി സംയോജിപ്പിക്കുമ്പോഴാണ് ഇതിന്റെ ശക്തി വെളിപ്പെടുന്നത്.
യൂണിയനുകളും പെർമ്യൂട്ടേഷനുകളും
ഒരു ടെംപ്ലേറ്റ് ലിറ്ററൽ ടൈപ്പിൽ ഒരു യൂണിയൻ ഉൾപ്പെടുമ്പോൾ, സാധ്യമായ എല്ലാ സ്ട്രിംഗ് പെർമ്യൂട്ടേഷനുകളും അടങ്ങുന്ന ഒരു പുതിയ യൂണിയനിലേക്ക് അത് വികസിക്കുന്നു. ഇത് കൃത്യമായി നിർവചിക്കപ്പെട്ട കോൺസ്റ്റന്റുകളുടെ ഒരു കൂട്ടം സൃഷ്ടിക്കുന്നതിനുള്ള ശക്തമായ ഒരു മാർഗമാണ്.
ഒരു കൂട്ടം CSS മാർജിൻ പ്രോപ്പർട്ടികൾ നിർവചിക്കുന്നത് സങ്കൽപ്പിക്കുക:
type Side = "top" | "right" | "bottom" | "left";
type MarginProperty = `margin-${Side}`;
MarginProperty-യുടെ ഫലമായുണ്ടാകുന്ന ടൈപ്പ് ഇതാണ്:
"margin-top" | "margin-right" | "margin-bottom" | "margin-left"
നിർദ്ദിഷ്ട സ്ട്രിംഗ് ഫോർമാറ്റുകൾ മാത്രം അനുവദനീയമായ ടൈപ്പ്-സേഫ് കമ്പോണന്റ് പ്രോപ്പുകൾ അല്ലെങ്കിൽ ഫംഗ്ഷൻ ആർഗ്യുമെന്റുകൾ സൃഷ്ടിക്കുന്നതിന് ഇത് അനുയോജ്യമാണ്.
ജെനറിക്സുമായി സംയോജിപ്പിക്കുന്നു
ജെനറിക്സുമായി ഉപയോഗിക്കുമ്പോൾ ടെംപ്ലേറ്റ് ലിറ്ററലുകൾ ശരിക്കും തിളങ്ങുന്നു. ചില ഇൻപുട്ടുകളെ അടിസ്ഥാനമാക്കി പുതിയ സ്ട്രിംഗ് ലിറ്ററൽ ടൈപ്പുകൾ നിർമ്മിക്കുന്ന ഫാക്ടറി ടൈപ്പുകൾ നിങ്ങൾക്ക് സൃഷ്ടിക്കാൻ കഴിയും.
type MakeEventListener
type UserListener = MakeEventListener<"user">; // "onUserChange"
type ProductListener = MakeEventListener<"product">; // "onProductChange"
ഡൈനാമിക്, ടൈപ്പ്-സേഫ് API-കൾ നിർമ്മിക്കുന്നതിനുള്ള താക്കോലാണ് ഈ പാറ്റേൺ. എന്നാൽ സ്ട്രിംഗിന്റെ കേസ് മാറ്റണമെങ്കിൽ, ഉദാഹരണത്തിന് "onUserChange" ലഭിക്കാൻ "user"-നെ "User" ആക്കി മാറ്റണമെങ്കിൽ എന്തുചെയ്യും? അവിടെയാണ് സ്ട്രിംഗ് മാനിപ്പുലേഷൻ ടൈപ്പുകൾ വരുന്നത്.
ടൂൾകിറ്റ്: ഇൻട്രിൻസിക് സ്ട്രിംഗ് മാനിപ്പുലേഷൻ ടൈപ്പുകൾ
ടെംപ്ലേറ്റ് ലിറ്ററലുകളെ കൂടുതൽ ശക്തമാക്കുന്നതിന്, ടൈപ്പ്സ്ക്രിപ്റ്റ് സ്ട്രിംഗ് ലിറ്ററലുകൾ കൈകാര്യം ചെയ്യുന്നതിനായി ഒരു കൂട്ടം ബിൽറ്റ്-ഇൻ ടൈപ്പുകൾ നൽകുന്നു. ഇവ ടൈപ്പ് സിസ്റ്റത്തിനായുള്ള യൂട്ടിലിറ്റി ഫംഗ്ഷനുകൾ പോലെയാണ്.
കേസ് മോഡിഫയറുകൾ: `Uppercase`, `Lowercase`, `Capitalize`, `Uncapitalize`
ഈ നാല് ടൈപ്പുകളും അവയുടെ പേരുകൾ സൂചിപ്പിക്കുന്നത് കൃത്യമായി ചെയ്യുന്നു:
Uppercase: മുഴുവൻ സ്ട്രിംഗ് ടൈപ്പിനെയും വലിയക്ഷരത്തിലേക്ക് മാറ്റുന്നു.type LOUD = Uppercase<"hello">; // "HELLO"Lowercase: മുഴുവൻ സ്ട്രിംഗ് ടൈപ്പിനെയും ചെറിയക്ഷരത്തിലേക്ക് മാറ്റുന്നു.type quiet = Lowercase<"WORLD">; // "world"Capitalize: സ്ട്രിംഗ് ടൈപ്പിലെ ആദ്യത്തെ അക്ഷരത്തെ വലിയക്ഷരത്തിലേക്ക് മാറ്റുന്നു.type Proper = Capitalize<"john">; // "John"Uncapitalize: സ്ട്രിംഗ് ടൈപ്പിലെ ആദ്യത്തെ അക്ഷരത്തെ ചെറിയക്ഷരത്തിലേക്ക് മാറ്റുന്നു.type variable = Uncapitalize<"PersonName">; // "personName"
നമ്മുടെ മുൻ ഉദാഹരണം വീണ്ടും പരിശോധിച്ച്, പരമ്പരാഗത ഇവന്റ് ഹാൻഡ്ലർ പേരുകൾ നിർമ്മിക്കാൻ Capitalize ഉപയോഗിച്ച് ഇത് മെച്ചപ്പെടുത്താം:
type MakeEventListener
type UserListener = MakeEventListener<"user">; // "onUserChange"
type ProductListener = MakeEventListener<"product">; // "onProductChange"
ഇപ്പോൾ നമുക്ക് എല്ലാ ഭാഗങ്ങളും ഉണ്ട്. സങ്കീർണ്ണവും യഥാർത്ഥ ലോകത്തിലെ പ്രശ്നങ്ങൾ പരിഹരിക്കുന്നതിന് അവ എങ്ങനെ സംയോജിക്കുന്നു എന്ന് നോക്കാം.
സമന്വയം: നൂതന പാറ്റേണുകൾക്കായി മൂന്നും സംയോജിപ്പിക്കുന്നു
ഇവിടെയാണ് സിദ്ധാന്തം പ്രായോഗികമാകുന്നത്. കണ്ടീഷണൽ ടൈപ്പുകൾ, ടെംപ്ലേറ്റ് ലിറ്ററലുകൾ, സ്ട്രിംഗ് മാനിപ്പുലേഷൻ എന്നിവ ഒരുമിച്ച് ചേർത്തുകൊണ്ട്, നമുക്ക് അവിശ്വസനീയമാംവിധം സങ്കീർണ്ണവും സുരക്ഷിതവുമായ ടൈപ്പ് ഡെഫനിഷനുകൾ നിർമ്മിക്കാൻ കഴിയും.
പാറ്റേൺ 1: പൂർണ്ണമായും ടൈപ്പ്-സേഫ് ആയ ഇവന്റ് എമിറ്റർ
ലക്ഷ്യം: on(), off(), emit() തുടങ്ങിയ മെത്തേഡുകളുള്ള ഒരു ജെനറിക് EventEmitter ക്ലാസ് നിർമ്മിക്കുക, അത് പൂർണ്ണമായും ടൈപ്പ്-സേഫ് ആയിരിക്കണം. ഇതിനർത്ഥം:
- മെത്തേഡുകളിലേക്ക് നൽകുന്ന ഇവന്റ് നെയിം ഒരു സാധുവായ ഇവന്റ് ആയിരിക്കണം.
emit()-ലേക്ക് നൽകുന്ന പേലോഡ് ആ ഇവന്റിനായി നിർവചിച്ച ടൈപ്പുമായി പൊരുത്തപ്പെടണം.on()-ലേക്ക് നൽകുന്ന കോൾബാക്ക് ഫംഗ്ഷൻ ആ ഇവന്റിനായുള്ള ശരിയായ പേലോഡ് ടൈപ്പ് സ്വീകരിക്കണം.
ആദ്യം, ഇവന്റ് പേരുകളും അവയുടെ പേലോഡ് ടൈപ്പുകളും തമ്മിലുള്ള ഒരു മാപ്പ് നമ്മൾ നിർവചിക്കുന്നു:
interface EventMap {
"user:created": { userId: number; name: string; };
"user:deleted": { userId: number; };
"product:added": { productId: string; price: number; };
}
ഇപ്പോൾ, നമുക്ക് ജെനറിക് EventEmitter ക്ലാസ് നിർമ്മിക്കാം. നമ്മുടെ EventMap ഘടനയെ എക്സ്റ്റൻഡ് ചെയ്യേണ്ട Events എന്ന ഒരു ജെനറിക് പാരാമീറ്റർ നമ്മൾ ഉപയോഗിക്കും.
class TypedEventEmitter
private listeners: { [K in keyof Events]?: ((payload: Events[K]) => void)[] } = {};
// `on` മെത്തേഡ് നമ്മുടെ Events മാപ്പിന്റെ ഒരു കീ ആയ `K` എന്ന ജെനറിക് ഉപയോഗിക്കുന്നു
on
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event]?.push(callback);
}
// `emit` മെത്തേഡ് പേലോഡ് ഇവന്റിന്റെ ടൈപ്പുമായി പൊരുത്തപ്പെടുന്നുണ്ടെന്ന് ഉറപ്പാക്കുന്നു
emit
this.listeners[event]?.forEach(callback => callback(payload));
}
}
നമുക്കിത് ഇൻസ്റ്റാൾ ചെയ്ത് ഉപയോഗിക്കാം:
const appEvents = new TypedEventEmitter
// ഇത് ടൈപ്പ്-സേഫ് ആണ്. പേലോഡ് ശരിയായി { userId: number; name: string; } എന്ന് ഇൻഫർ ചെയ്യപ്പെടുന്നു
appEvents.on("user:created", (payload) => {
console.log(`User created: ${payload.name} (ID: ${payload.userId})`);
});
// EventMap-ൽ "user:updated" ഒരു കീ അല്ലാത്തതിനാൽ ടൈപ്പ്സ്ക്രിപ്റ്റ് ഇവിടെ പിശക് കാണിക്കും
// appEvents.on("user:updated", () => {}); // Error!
// പേലോഡിൽ 'name' പ്രോപ്പർട്ടി ഇല്ലാത്തതിനാൽ ടൈപ്പ്സ്ക്രിപ്റ്റ് ഇവിടെ പിശക് കാണിക്കും
// appEvents.emit("user:created", { userId: 123 }); // Error!
പല ആപ്ലിക്കേഷനുകളിലും പരമ്പരാഗതമായി വളരെ ഡൈനാമിക് ആയതും പിശകുകൾക്ക് സാധ്യതയുള്ളതുമായ ഒരു ഭാഗത്തിന് ഈ പാറ്റേൺ കംപൈൽ-ടൈം സുരക്ഷ നൽകുന്നു.
പാറ്റേൺ 2: നെസ്റ്റഡ് ഒബ്ജക്റ്റുകൾക്ക് ടൈപ്പ്-സേഫ് പാത്ത് ആക്സസ്
ലക്ഷ്യം: ഒരു നെസ്റ്റഡ് ഒബ്ജക്റ്റ് T-യിൽ ഒരു ഡോട്ട്-നൊട്ടേഷൻ സ്ട്രിംഗ് പാത്ത് P (ഉദാ. "user.address.city") ഉപയോഗിച്ച് ഒരു മൂല്യത്തിന്റെ ടൈപ്പ് നിർണ്ണയിക്കാൻ കഴിയുന്ന PathValue എന്ന ഒരു യൂട്ടിലിറ്റി ടൈപ്പ് നിർമ്മിക്കുക.
ഇത് റിക്കേഴ്സീവ് കണ്ടീഷണൽ ടൈപ്പുകൾ പ്രദർശിപ്പിക്കുന്ന വളരെ നൂതനമായ ഒരു പാറ്റേണാണ്.
ഇതിന്റെ നിർവ്വചനം താഴെ നൽകുന്നു, അത് നമ്മൾ വിശദീകരിക്കുന്നതാണ്:
type PathValue
? Key extends keyof T
? PathValue
: never
: P extends keyof T
? T[P]
: never;
ഒരു ഉദാഹരണത്തിലൂടെ നമുക്ക് ഇതിന്റെ ലോജിക് പരിശോധിക്കാം: PathValue
- പ്രാരംഭ കോൾ:
Pഎന്നത്"a.b.c"ആണ്. ഇത് ടെംപ്ലേറ്റ് ലിറ്ററലായ`${infer Key}.${infer Rest}`-മായി പൊരുത്തപ്പെടുന്നു. Key"a"ആയി ഇൻഫർ ചെയ്യപ്പെടുന്നു.Rest"b.c"ആയി ഇൻഫർ ചെയ്യപ്പെടുന്നു.- ആദ്യ റിക്കർഷൻ: ടൈപ്പ്
"a"എന്നത്MyObject-ന്റെ ഒരു കീ ആണോ എന്ന് പരിശോധിക്കുന്നു. അതെ എങ്കിൽ, അത്PathValueഎന്ന് റിക്കേഴ്സീവായി വിളിക്കുന്നു. - രണ്ടാം റിക്കർഷൻ: ഇപ്പോൾ,
Pഎന്നത്"b.c"ആണ്. ഇത് വീണ്ടും ടെംപ്ലേറ്റ് ലിറ്ററലുമായി പൊരുത്തപ്പെടുന്നു. Key"b"ആയി ഇൻഫർ ചെയ്യപ്പെടുന്നു.Rest"c"ആയി ഇൻഫർ ചെയ്യപ്പെടുന്നു.- ടൈപ്പ്
"b"എന്നത്MyObject["a"]-ന്റെ ഒരു കീ ആണോ എന്ന് പരിശോധിച്ച്,PathValueഎന്ന് റിക്കേഴ്സീവായി വിളിക്കുന്നു. - ബേസ് കേസ്: ഒടുവിൽ,
Pഎന്നത്"c"ആണ്. ഇത്`${infer Key}.${infer Rest}`-മായി പൊരുത്തപ്പെടുന്നില്ല. ടൈപ്പ് ലോജിക് രണ്ടാമത്തെ കണ്ടീഷണലിലേക്ക് പോകുന്നു:P extends keyof T ? T[P] : never. - ടൈപ്പ്
"c"എന്നത്MyObject["a"]["b"]-ന്റെ ഒരു കീ ആണോ എന്ന് പരിശോധിക്കുന്നു. അതെ എങ്കിൽ, ഫലംMyObject["a"]["b"]["c"]ആയിരിക്കും. ഇല്ലെങ്കിൽ, അത്neverആയിരിക്കും.
ഒരു ഹെൽപ്പർ ഫംഗ്ഷനോടുകൂടിയ ഉപയോഗം:
declare function get
const myObject = {
user: {
name: "Alice",
address: {
city: "Wonderland",
zip: 12345
}
}
};
const city = get(myObject, "user.address.city"); // const city: string
const zip = get(myObject, "user.address.zip"); // const zip: number
const invalid = get(myObject, "user.email"); // const invalid: never
ഈ ശക്തമായ ടൈപ്പ്, പാത്തുകളിലെ ടൈപ്പിംഗ് പിശകുകൾ മൂലമുണ്ടാകുന്ന റൺടൈം എററുകൾ തടയുകയും, സങ്കീർണ്ണമായ API റെസ്പോൺസുകളുമായി ഇടപെടുന്ന ആഗോള ആപ്ലിക്കേഷനുകളിൽ സാധാരണയായി കാണുന്ന ആഴത്തിലുള്ള ഡാറ്റാ ഘടനകൾക്ക് മികച്ച ടൈപ്പ് ഇൻഫെറൻസ് നൽകുകയും ചെയ്യുന്നു.
മികച്ച രീതികളും പ്രകടന പരിഗണനകളും
ഏതൊരു ശക്തമായ ഉപകരണത്തെയും പോലെ, ഈ ഫീച്ചറുകൾ വിവേകത്തോടെ ഉപയോഗിക്കേണ്ടത് പ്രധാനമാണ്.
- വായനാക്ഷമതയ്ക്ക് മുൻഗണന നൽകുക: സങ്കീർണ്ണമായ ടൈപ്പുകൾ പെട്ടെന്ന് വായിക്കാൻ ബുദ്ധിമുട്ടുള്ളതായി മാറും. അവയെ ചെറിയ, നല്ല പേരുള്ള ഹെൽപ്പർ ടൈപ്പുകളായി വിഭജിക്കുക. സങ്കീർണ്ണമായ റൺടൈം കോഡിൽ ചെയ്യുന്നതുപോലെ, ലോജിക് വിശദീകരിക്കാൻ കമന്റുകൾ ഉപയോഗിക്കുക.
- `never` ടൈപ്പ് മനസ്സിലാക്കുക: കണ്ടീഷണൽ ടൈപ്പുകളിൽ പിശകുകൾ കൈകാര്യം ചെയ്യുന്നതിനും യൂണിയനുകൾ ഫിൽട്ടർ ചെയ്യുന്നതിനുമുള്ള നിങ്ങളുടെ പ്രധാന ഉപകരണമാണ് `never` ടൈപ്പ്. ഒരിക്കലും സംഭവിക്കാൻ പാടില്ലാത്ത ഒരു അവസ്ഥയെ ഇത് പ്രതിനിധീകരിക്കുന്നു.
- റിക്കർഷൻ പരിധികൾ ശ്രദ്ധിക്കുക: ടൈപ്പ്സ്ക്രിപ്റ്റിന് ടൈപ്പ് ഇൻസ്റ്റാന്റിയേഷനായി ഒരു റിക്കർഷൻ ഡെപ്ത് പരിധിയുണ്ട്. നിങ്ങളുടെ ടൈപ്പുകൾ വളരെ ആഴത്തിലുള്ളതോ അനന്തമായി റിക്കേഴ്സീവോ ആണെങ്കിൽ, കംപൈലർ പിശക് കാണിക്കും. നിങ്ങളുടെ റിക്കേഴ്സീവ് ടൈപ്പുകൾക്ക് വ്യക്തമായ ഒരു ബേസ് കേസ് ഉണ്ടെന്ന് ഉറപ്പാക്കുക.
- IDE പ്രകടനം നിരീക്ഷിക്കുക: വളരെ സങ്കീർണ്ണമായ ടൈപ്പുകൾ ചിലപ്പോൾ ടൈപ്പ്സ്ക്രിപ്റ്റ് ലാംഗ്വേജ് സെർവറിന്റെ പ്രകടനത്തെ ബാധിച്ചേക്കാം, ഇത് നിങ്ങളുടെ എഡിറ്ററിലെ ഓട്ടോകംപ്ലീഷനും ടൈപ്പ് ചെക്കിംഗും മന്ദഗതിയിലാക്കാൻ ഇടയാക്കും. നിങ്ങൾക്ക് വേഗത കുറവ് അനുഭവപ്പെട്ടാൽ, ഒരു സങ്കീർണ്ണമായ ടൈപ്പ് ലളിതമാക്കാനോ വിഭജിക്കാനോ കഴിയുമോ എന്ന് നോക്കുക.
- എവിടെ നിർത്തണമെന്ന് അറിയുക: ഈ ഫീച്ചറുകൾ ടൈപ്പ്-സുരക്ഷയുടെയും ഡെവലപ്പർ അനുഭവത്തിന്റെയും സങ്കീർണ്ണമായ പ്രശ്നങ്ങൾ പരിഹരിക്കുന്നതിനാണ്. ലളിതമായ ടൈപ്പുകളെ ഓവർ-എഞ്ചിനീയർ ചെയ്യാൻ അവ ഉപയോഗിക്കരുത്. വ്യക്തതയും സുരക്ഷയും വർദ്ധിപ്പിക്കുക എന്നതാണ് ലക്ഷ്യം, അനാവശ്യമായ സങ്കീർണ്ണത ചേർക്കുകയല്ല.
ഉപസംഹാരം
കണ്ടീഷണൽ ടൈപ്പുകൾ, ടെംപ്ലേറ്റ് ലിറ്ററലുകൾ, സ്ട്രിംഗ് മാനിപ്പുലേഷൻ ടൈപ്പുകൾ എന്നിവ ഒറ്റപ്പെട്ട ഫീച്ചറുകൾ മാത്രമല്ല; അവ ടൈപ്പ് ലെവലിൽ സങ്കീർണ്ണമായ ലോജിക് നിർവഹിക്കുന്നതിനുള്ള ഒരു ശക്തമായി സംയോജിപ്പിച്ച സിസ്റ്റമാണ്. ലളിതമായ അനോട്ടേഷനുകൾക്കപ്പുറം പോകാനും സ്വന്തം ഘടനയെയും നിയന്ത്രണങ്ങളെയും കുറിച്ച് ആഴത്തിൽ ബോധമുള്ള സിസ്റ്റങ്ങൾ നിർമ്മിക്കാനും അവ നമ്മളെ പ്രാപ്തരാക്കുന്നു.
ഈ മൂന്നെണ്ണത്തിലും പ്രാവീണ്യം നേടുന്നതിലൂടെ, നിങ്ങൾക്ക്:
- സ്വയം-ഡോക്യുമെന്റിംഗ് API-കൾ സൃഷ്ടിക്കുക: ടൈപ്പുകൾ തന്നെ ഡോക്യുമെന്റേഷനായി മാറുന്നു, ഡെവലപ്പർമാരെ അവ ശരിയായി ഉപയോഗിക്കാൻ നയിക്കുന്നു.
- ഒരു വിഭാഗം ബഗ്ഗുകൾ പൂർണ്ണമായും ഒഴിവാക്കുക: ടൈപ്പ് പിശകുകൾ പ്രൊഡക്ഷനിൽ ഉപയോക്താക്കൾ കണ്ടെത്തുന്നതിന് പകരം കംപൈൽ-ടൈമിൽ തന്നെ കണ്ടെത്തുന്നു.
- ഡെവലപ്പർ അനുഭവം മെച്ചപ്പെടുത്തുക: നിങ്ങളുടെ കോഡ്ബേസിന്റെ ഏറ്റവും ഡൈനാമിക് ഭാഗങ്ങളിൽ പോലും സമ്പന്നമായ ഓട്ടോകംപ്ലീഷനും ഇൻലൈൻ പിശക് സന്ദേശങ്ങളും ആസ്വദിക്കുക.
ഈ നൂതന കഴിവുകൾ ഉൾക്കൊള്ളുന്നത് ടൈപ്പ്സ്ക്രിപ്റ്റിനെ ഒരു സുരക്ഷാ വലയിൽ നിന്ന് വികസനത്തിലെ ഒരു ശക്തമായ പങ്കാളിയായി മാറ്റുന്നു. സങ്കീർണ്ണമായ ബിസിനസ്സ് ലോജിക്കും ഇൻവേരിയന്റുകളും ടൈപ്പ് സിസ്റ്റത്തിലേക്ക് നേരിട്ട് എൻകോഡ് ചെയ്യാൻ ഇത് നിങ്ങളെ അനുവദിക്കുന്നു, നിങ്ങളുടെ ആപ്ലിക്കേഷനുകൾ ആഗോള പ്രേക്ഷകർക്കായി കൂടുതൽ കരുത്തുറ്റതും പരിപാലിക്കാൻ കഴിയുന്നതും സ്കെയിലബിളും ആണെന്ന് ഉറപ്പാക്കുന്നു.