TypeScript-ன் புதிய const type parameter தொடரியல் (syntax), அழைப்பவர்கள் (callers) எல்லா இடங்களிலும் as const என்பதைச் சேர்க்க வேண்டிய கட்டாயமின்றி, ஒரு செயல்பாடு (function) அதன் literal வகைகளை (literal types) அப்படியே வைத்திருக்க அனுமதிக்கிறது. இது வகை-விரிவாக்கப் பிழைகளின் (type-widening bugs) பொதுவான ஆதாரத்தைக் குறைக்கிறது.

Generic குறியீடுகளைத் துரத்தும் widening சிக்கல்

ஒரு generic செயல்பாடு ஒரு object literal-ஐப் பெறும்போது, compiler அந்த literal பண்பை (property) அதன் பரந்த primitive வகையாக விரிவுபடுத்துகிறது (widens).

function call<T>(arg: T) {}
call({ method: "GET" })   // T is inferred as { method: string }

"GET" என்ற literal, string ஆகச் சுருங்கிவிடுகிறது. discriminated unions அல்லது template-literal extraction போன்ற துல்லியமான மதிப்பைச் சார்ந்திருக்கும் அடுத்தகட்ட குறியீடுகள் (downstream code) உடைந்துவிடும், ஏனெனில் அந்த வகை (type) இனி துல்லியமான literal-ஐக் கொண்டிருக்காது. டெவலப்பர்கள் நீண்டகாலமாக அழைப்பு இடத்தில் (call site) { method: "GET" } as const என்று எழுதுவதன் மூலம் இதைச் சமாளித்து வருகின்றனர்; இது compiler-இடம் அந்த literal-ஐ அப்படியே வைத்திருக்கச் சொல்கிறது, ஆனால் அந்தத் தீர்வு அழைப்பவரின் கையில் மட்டுமே உள்ளது, செயல்பாட்டின் வரையறையில் (function's definition) இல்லை.

Const type parameters: ஒரு signature-நிலை தீர்வு

ஒரு type parameter-இல் உள்ள புதிய const modifier, அந்த generic argument-க்கான மிகவும் குறுகிய சாத்தியமான (narrowest possible) வகையைத் தீர்மானிக்க (infer) compiler-இடம் கூறுகிறது. ஒரு செயல்பாட்டை function foo<const T>(arg: T) என்று அறிவிப்பது, அழைப்பவர் as const என்று எழுதியது போலவே T-ஐ தானாகவே செயல்பட வைக்கும்.

  • String, number, boolean literals அவற்றின் துல்லியமான மதிப்புகளாகவே இருக்கும் (string-க்கு பதிலாக "GET").
  • Arrays, ஒவ்வொரு உறுப்பும் துல்லியமான வகையைக் கொண்ட readonly tuples-களாக மாறும்.
  • Objects, ஒவ்வொரு அடுக்கு நிலையிலும் (nesting level) literal வகைகளைப் பாதுகாக்கும் வகையில் ஆழமான readonly கட்டமைப்புகளாக (deeply readonly structures) மாறும்.

இந்தத் தடையானது (constraint) செயல்பாட்டின் signature-இல் இருப்பதால், ஒவ்வொரு அழைப்பவரும் தானாகவே பயனடைகிறார்கள்; ஒரு cast-ஐ மறப்பது இனி பிழைகளுக்கு (unsoundness) வழிவகுக்காது.

ஏன் இது வழக்கமான as const முறையை விடச் சிறந்தது

as const என்பது ஒரு caller-side தீர்வு. ஒரு generic செயல்பாட்டைப் பயன்படுத்தும் ஒவ்வொருவரும் அந்த assertion-ஐச் சேர்க்க நினைவில் கொள்ள வேண்டும். ஒரே ஒரு அழைப்பைத் தவறவிட்டாலும், type safety மறைந்துவிடும். Const type parameter இந்தப் பொறுப்பை API வடிவமைப்பிற்கே கொண்டு வருகிறது: "நீங்கள் எதைக் கொடுத்தாலும் அதன் மிகக் குறுகிய வடிவமே எனக்குத் தேவை" என்று செயல்பாடு அறிவிக்கிறது, மேலும் compiler அதை நடைமுறைப்படுத்துகிறது.

Generic builders, configuration factories அல்லது ஒரு புலத்தின் (field) literal மதிப்பு type logic-ஐத் தீர்மானிக்கும் எந்தவொரு API-யையும் வழங்கும் நூலகங்கள் (libraries) மற்றும் பயன்பாட்டுத் கருவிகளுக்கு (utilities) இந்த மாற்றம் மிகவும் முக்கியமானது. நூலகத்தின் ஆசிரியர், அடுத்தகட்ட குறியீடுகளைக் கண்காணிக்காமலேயே சரியான inference-ஐ உறுதிப்படுத்த முடியும்.

இதனால் பயனடையும் நிஜ உலகச் சூழல்கள்

  • Configuration builders – environment பெயர்கள் ("dev" | "prod") literal-களாகவே இருக்கும், இது கூடுதல் casts இன்றி discriminated-union சோதனைகளைச் செய்ய அனுமதிக்கிறது.
  • API route definitions – path strings துல்லியமாக இருக்கும், இது template-literal வகைகள் மூலம் அளவுருக்களை (parameters) பிரித்தெடுக்க அனுமதிக்கிறது ("/users/:id"\/users/${string}``).
  • State-machine helpers – method chaining மூலம் state அடையாளங்கள் நிலையான literal-களாகவே இருக்கும், இது தற்செயலான state பொருத்தமின்மையைத் (state mismatches) தடுக்கிறது.

ஒவ்வொரு சூழலிலும், const parameter மீண்டும் மீண்டும் வரும் as const boilerplate-ஐ நீக்குகிறது மற்றும் நுணுக்கமான பிழைகள் (subtle bugs) நுழைவதற்கான வாய்ப்பைக் குறைக்கிறது.

satisfies operator-உடன் இணைத்துப் பயன்படுத்துதல்

satisfies operator ஒரு மதிப்பு அதன் அசல் literal தகவலைப் பாதுகாக்கும் அதே வேளையில், அது ஒரு structural type-க்கு இணங்குவதை உறுதி செய்கிறது. இவை இரண்டையும் சேர்த்துப் பயன்படுத்துவது சிறந்த பலனைத் தரும்: const parameters குறுகிய inference-ஐ வழங்குகின்றன, மேலும் satisfies அந்த மதிப்பு தேவையான வடிவத்தில் இருப்பதை உறுதி செய்கிறது.

function makeConfig<const C>(cfg: C) {
  // cfg is inferred with exact literals
}
const cfg = {
  env: "staging",
  ports: [8080, 8443],
} satisfies { env: string; ports: number[] };
makeConfig(cfg); // works, literals stay intact

எப்போது as const-ஐத் தொடர வேண்டும்

செயல்பாட்டின் signature-ஐ நீங்கள் கட்டுப்படுத்தும் போது const parameter சிறப்பாகச் செயல்படும். இந்த modifier இல்லாத மூன்றாம் தரப்பு (third-party) செயல்பாடுகளைக் கையாளும்போதோ அல்லது ஒரு local variable-க்காக ஒருமுறை மட்டும் literal-ஐப் பாதுகாக்க வேண்டியபோதோ, as const சரியான கருவியாக இருக்கும். அழைக்கப்பட்ட API-யை மாற்றாமல் ஒரு மதிப்பை உறைய வைக்க (freeze) இது இன்னும் சிறந்த வழியாகவே உள்ளது.

அடுத்து கவனிக்க வேண்டியவை

இந்த அம்சம் இன்னும் புதியது என்பதால், tooling மற்றும் community முறைகள் உருவாகி வருகின்றன. autocomplete மற்றும் quick-fix பரிந்துரைகளில் இந்த புதிய தொடரியலைத் தெரியப்படுத்தும் வகையில் IDE ஆதரவு மேம்படுத்தப்படும் என்று எதிர்பார்க்கலாம். நூலகப் பராமரிப்பாளர்கள் (library maintainers) மீது கவனம் செலுத்துங்கள்: பலர் பொதுவான generics-களை const parameters-களுக்கு மாற்றத் தொடங்குவார்கள், இது இதற்கு முன்பு வெளிப்படையான as const casts-களைச் சார்ந்திருந்த குறியீடுகளுக்கு breaking changes-களை ஏற்படுத்தக்கூடும்.

சுருக்கம் (Takeaway): literal பாதுகாப்பை நேரடியாக ஒரு செயல்பாட்டின் type parameters-இல் இணைப்பதன் மூலம், TypeScript-ன் const type parameters, widening பிழைகளின் பொதுவான ஆதாரத்தை நீக்கி, பாதுகாப்பை அழைப்பவரிடமிருந்து API வடிவமைப்பிற்குத் திரும்பத் தருகிறது. நீங்கள் உருவாக்கும் எந்தவொரு generic entry point-க்கும் இதைப் பயன்படுத்துங்கள்; local மதிப்புகள் அல்லது வெளிப்புற API-களுக்கு மட்டும் as const-ஐப் பயன்படுத்துங்கள்.