TypeScript ప్రాజెక్టులు పెరుగుతాయి. ఫైళ్లు పెరిగిపోతాయి. డిపెండెన్సీలు చిక్కుముడి పడతాయి. చివరికి, మీ బిల్డ్ ప్రాసెస్ మీ లాజిక్ సంక్లిష్టత వల్ల కాకుండా, ఒకే ఒక్క డిక్లరేషన్ ఫైల్ను రాయడానికి ముందు కంపైలర్ మొత్తం ప్రపంచాన్ని చదవాల్సి రావడం వల్ల ఆగిపోతుంది.
TypeScript 6.0 దీనిని isolatedDeclarations ద్వారా పరిష్కరిస్తుంది. ఈ ఫీచర్ .d.ts ఫైళ్లు ఎలా తయారవుతాయో అనే విధానాన్ని మారుస్తుంది. డిక్లరేషన్ ఎమిషన్ను (declaration emission) పూర్తి టైప్-చెకింగ్ పైప్లైన్తో ముడిపెట్టే బదులు, ఇది ప్రతి సోర్స్ ఫైల్ను విడిగా (in isolation) పరిశీలించి ఆ ఫైళ్లను ఎమిట్ చేయడానికి కంపైలర్కు అనుమతిస్తుంది. దీని ఫలితంగా, మీ డిపెండెన్సీ గ్రాఫ్ను ఒక్కొక్క లింక్ ద్వారా వెతకడానికి బదులుగా, వేల సంఖ్యలో ఫైళ్లపై సమాంతరంగా (in parallel) రన్ చేయగల బిల్డ్ ప్రాసెస్ లభిస్తుంది.
అసలైన అడ్డంకి (The Real Bottleneck)
ప్రస్తుతం, డిక్లరేషన్ ఫైళ్లను జనరేట్ చేయడం అనేది ఒక సీరియల్ ఆపరేషన్. మీరు --declaration ని ఎనేబుల్ చేసి కంపైలర్ను రన్ చేసినప్పుడు, ఒక మాడ్యూల్ తాకిన ప్రతి టైప్ను పూర్తిగా అర్థం చేసుకునే వరకు TypeScript ఆ మాడ్యూల్ కోసం .d.ts ఫైల్ను ఎమిట్ చేయలేదు. ఒకవేళ utils.ts అనేది types.ts నుండి టైప్లను ఇంపోర్ట్ చేస్తే, మరియు types.ts అనేది api.ts నుండి ఏదైనా తీసుకుంటే, utils.ts ఏమి ఎక్స్పోర్ట్ చేస్తుందో వివరించడానికి ముందు కంపైలర్ ఆ చైన్ను పరిష్కరించాల్సి ఉంటుంది.
ఒక పెద్ద మోనోరెపో (monorepo)లో, ఈ ప్రభావం చాలా తీవ్రంగా ఉంటుంది. మీ ఇంపోర్ట్ గ్రాఫ్ యొక్క రూట్ (root) దగ్గర ఉన్న ఒకే ఒక్క ఫైల్, వందలాది డౌన్స్ట్రీమ్ ఫైళ్ల డిక్లరేషన్ ఎమిషన్ను అడ్డుకోగలదు. మీ CPUకి ఎనిమిది కోర్లు ఉండవచ్చు, కానీ TypeScript ప్రతి ఇంటర్ఫేస్ యొక్క రూపాన్ని ప్యాకేజీ బౌండరీల ద్వారా కష్టపడి పునర్నిర్మించే క్రమంలో, అందులో ఏడు కోర్లు ఖాళీగా కూర్చుంటాయి. కంపైలర్ అవసరమైన పనిని చేస్తోంది, కానీ టైప్ చెకింగ్ మరియు డిక్లరేషన్ ఎమిషన్ మధ్య ఉన్న అనుసంధానం (coupling) వల్ల, మీరు కేవలం పబ్లిక్ సర్ఫేస్ టైప్లను మాత్రమే డిస్క్లోకి రాయాలనుకున్నా, ఫైల్స్ మధ్య విశ్లేషణకు అయ్యే పూర్తి ఖర్చును భరించాల్సి వస్తుంది.
isolatedDeclarations నియమాలను ఎలా మారుస్తుంది
isolatedDeclarations ఆ అనుసంధానాన్ని (coupling) విడగొడుతుంది. ఈ ఫ్లాగ్ ఎనేబుల్ చేసినప్పుడు, కంపైలర్ వేరే ఏ ఫైల్ను అడగకుండానే ఒక సోర్స్ ఫైల్ కోసం .d.ts ఫైల్ను ఎమిట్ చేయడానికి అంగీకరిస్తుంది. ఇది ఒక సరళమైన ఒప్పందాన్ని (contract) కోరుకోవడం ద్వారా జరుగుతుంది: ఎక్స్పోర్ట్ చేయబడిన ప్రతి సింబల్ (symbol), అది డిక్లేర్ చేయబడిన చోటే స్పష్టమైన, కనిపించే టైప్ అనోటేషన్ను (type annotation) కలిగి ఉండాలి.
సోర్స్లోనే పూర్తి టైప్ కంపైలర్కు కనిపిస్తే, దానికి ఇన్ఫరెన్స్ (inference) చేయాల్సిన అవసరం లేదు. అది ఇంపోర్ట్లను వెతకాల్సిన అవసరం లేదు. వేరొక ఫైల్లోని User అనే ఐడెంటిఫైయర్ ఒక ఇంటర్ఫేస్, టైప్ ఏలియాస్ లేదా క్లాస్ అనేది తెలుసుకోవాల్సిన అవసరం లేదు. మీరు ఏమి రాశారో సరిగ్గా అదే అది ఎమిట్ చేస్తుంది.
దీని అర్థం ఫైల్ A మరియు ఫైల్ B తమ డిక్లరేషన్లను ఏకకాలంలో జనరేట్ చేయగలవు. ఒక బిల్డ్ ఆర్కెస్ట్రేటర్ ప్రతి ఫైల్ను వేర్వేరు థ్రెడ్కు పంపగలదు. పూర్తి టైప్ చెకర్ లేకపోవడం వల్ల గతంలో .d.ts జనరేషన్ను స్కిప్ చేసిన ఫాస్ట్ ట్రాన్స్పైలర్లు (fast transpilers) కూడా ఇప్పుడు డిక్లరేషన్ ఫైళ్లను ఉత్పత్తి చేయగలవు, ఎందుకంటే ఈ పని పూర్తిగా సింటాక్టిక్ (syntactic) గా మారుతుంది.
లాభనష్టాల సమతుల్యత (The Tradeoff): స్పష్టంగా రాయండి
వేగం ఉచితంగా రాదు. మీరు ఎక్స్పోర్ట్ చేసే దేనికైనా టైప్ ఇన్ఫరెన్స్ (type inference) పై ఆధారపడటం ఆపాలి. ప్రతి పబ్లిక్ ఫంక్షన్, క్లాస్, వేరియబుల్ మరియు కాన్స్టెంట్ యొక్క టైప్ను స్పష్టంగా పేర్కొనాలి. ఒకవేళ TypeScript రిటర్న్ స్టేట్మెంట్ను చూడటం ద్వారా లేదా జనరిక్ ఆర్గ్యుమెంట్ను పరిష్కరించడం ద్వారా టైప్ను లెక్కించాల్సి వస్తే, isolatedDeclarations ఎర్రర్ను చూపుతుంది.
ఇది ప్రాక్టికల్గా ఎలా ఉంటుందో ఇక్కడ చూడండి. ఫ్లాగ్ లేకుండా, మీరు ఇలా రాసి ఉండవచ్చు:
export function fetchUser(id: number) {
return fetch(`/users/${id}`).then(r => r.json());
}
TypeScript fetch, ఆపై Promise.prototype.then, ఆపై r.json()ను రిటర్న్ చేసే అనోనిమస్ ఫంక్షన్ను పరిశీలించడం ద్వారా రిటర్న్ టైప్ను ఇన్ఫర్ చేస్తుంది. .d.tsని ఎమిట్ చేయడానికి, కంపైలర్ ఆ విశ్లేషణ అంతటినీ చేయాల్సి ఉంటుంది.
isolatedDeclarations ఎనేబుల్ చేసినప్పుడు, మీరు ఎక్స్పోర్ట్ను అనోటేట్ చేయాలి:
interface User {
id: number;
email: string;
}
export function fetchUser(id: number): Promise<User> {
return fetch(`/users/${id}`).then(r => r.json());
}
ఇప్పుడు కంపైలర్ వెంటనే Promise<User>ను చూస్తుంది. అది డిక్లరేషన్ను ఎమిట్ చేసి ముందుకు వెళ్తుంది.
ఈ నియమం విస్తృతంగా వర్తిస్తుంది. ఎక్స్పోర్ట్ చేయబడిన అర్రేలకు (arrays) వాటి ఎలిమెంట్స్ నుండి ఇన్ఫర్ చేయబడే బదులు స్పష్టమైన టైప్లు అవసరం. ఎక్స్పోర్ట్ చేయబడిన ఆబ్జెక్ట్ల ఆకృతి (shape) వినియోగదారులకు ముఖ్యమైతే, వాటికి స్పష్టమైన టైప్ అనోటేషన్లు అవసరం. జనరిక్ ఫంక్షన్లకు వాటి రిటర్న్ టైప్లు మరియు కన్స్ట్రైంట్లు (constraints) డిక్లరేషన్ సైట్లోనే కనిపించాలి. పూర్తి స్థాయిలో వ్రాయబడిన నేమ్డ్ టైప్ ఏలియాస్ను ఇవ్వకుండా, మీరు ఒక సంక్లిష్టమైన మ్యాప్డ్ టైప్ (mapped type) ఫలితాన్ని ఎక్స్పోర్ట్ చేయలేరు.
దీని వల్ల కలిగే ప్రయోజనం ఏమిటంటే, మీ పబ్లిక్ API స్వయంగా డాక్యుమెంట్ చేయబడినట్లు (self-documenting) మారుతుంది. వినియోగదారులు—మరియు కంపైలర్—ఇంకా మీ ఇంప్లిమెంటేషన్ వివరాల నుండి మీ ఉద్దేశాన్ని రివర్స్-ఇంజనీర్ చేయాల్సిన అవసరం లేదు. టైప్లు ఒక స్పష్టమైన ఒప్పందంలా పనిచేస్తాయి.
సమయం ఎక్కడ ఆదా అవుతుంది
ఒక పెద్ద కోడ్బేస్లో, దీని ప్రభావం తక్షణమే కనిపిస్తుంది. డిక్లరేషన్ ఎమిషన్ అనేది బిల్డ్ ప్రక్రియలో అతిపెద్ద అడ్డంకి కాకపోవడం వల్ల, నిమిషాల తరబడి సాగే బిల్డ్ సమయం సెకన్లకు తగ్గుతుంది. ప్రతి ఫైల్ స్వతంత్రంగా ఎమిట్ అవుతుంది, కాబట్టి ఈ ప్రక్రియ మీ ఇంపోర్ట్ గ్రాఫ్ లోతుతో కాకుండా, మీ వద్ద ఉన్న కోర్ల సంఖ్యతో స్కేల్ అవుతుంది.
ఇది మీరు ఉపయోగించగల సాధనాలను (tools) కూడా మారుస్తుంది. TypeScriptని JavaScriptగా మార్చడంలో esbuild మరియు swc వంటి Transpilers ఇప్పటికే అత్యంత వేగంగా పనిచేస్తున్నాయి, కానీ చాలా బృందాలు కేవలం .d.ts ఫైళ్లను రూపొందించడానికి మాత్రమే విడిగా tscని ఉపయోగిస్తున్నాయి. isolatedDeclarationsతో, ఆ వేగవంతమైన సాధనాలు రెండు పనులను చేయగలవు. డిక్లరేషన్లను (declarations) రూపొందించడానికి అవి TypeScript యొక్క పూర్తి టైప్ సిస్టమ్ను అనుకరించాల్సిన అవసరం లేదు; అవి కేవలం సింటాక్స్ను విశ్లేషించి (parse), మీరు అందించిన స్పష్టమైన (explicit) టైపులను కాపీ చేస్తే సరిపోతుంది. ఇది ప్రత్యామ్నాయ టూల్చైన్లతో (toolchains) ఎండ్-టు-ఎండ్ TypeScript బిల్డ్లను మరింత సాధ్యతరం చేస్తుంది.
డిస్ట్రిబ్యూటెడ్ మరియు ఇంక్రిమెంటల్ బిల్డ్లు కూడా సులభతరం అవుతాయి. కంటిన్యూయస్ ఇంటిగ్రేషన్ (continuous integration)లో, ఒక రిమోట్ క్యాష్ లేదా షార్డెడ్ బిల్డ్ (sharded build), ఒక ప్యాకేజీ యొక్క పూర్తి ట్రాన్సిటివ్ డిపెండెన్సీ గ్రాఫ్ను ముందుగా డౌన్లోడ్ చేయకుండానే దాని డిక్లరేషన్లను విడుదల చేయగలదు. సోర్స్ కోడ్లో టైపులు స్పష్టంగా ఉంటే, బిల్డ్ షార్డ్కు అవసరమైనవన్నీ అందుబాటులో ఉంటాయి.
ఏవి మారవు
ఈ పరిమితి కేవలం ఎక్స్పోర్ట్లకు (exports) మాత్రమే వర్తిస్తుంది. ఒక మాడ్యూల్ లోపల, అంతా యథావిధిగా కొనసాగుతుంది. లోకల్ వేరియబుల్స్, ప్రైవేట్ క్లాస్ మెంబర్స్ మరియు ఎక్స్పోర్ట్ చేయని హెల్పర్ ఫంక్షన్లు ఇప్పటికీ పూర్తి టైప్ ఇన్ఫరెన్స్ (type inference)పై ఆధారపడవచ్చు. TypeScript ఎటువంటి ఫిర్యాదు లేకుండా లూప్ వేరియబుల్ లేదా క్లోజర్ పారామీటర్ యొక్క టైప్ను సులభంగా ఇన్ఫర్ చేయగలదు.
export function calculateTotal(items: Item[]): number {
// Local variable: inference is fine
const taxRate = 0.08;
// Private class member inside a local class: inference is fine
class Helper {
private cache = new Map();
}
return items.reduce((sum, item) => sum + item.price * (1 + taxRate), 0);
}
ఎక్స్పోర్ట్ చేయబడిన ఫంక్షన్ సిగ్నేచర్కు మాత్రమే అనోటేషన్ (annotation) అవసరమవుతుంది. అంతర్గత యంత్రాంగం (internal machinery) సరళంగా మరియు వ్యక్తీకరణత్మకంగా ఉంటుంది. ఇది కోడ్ రాసే భారాన్ని (authoring burden) తట్టుకోగలిగేలా చేస్తుంది. మీరు ప్రతిచోటా పూర్తిగా ఎక్స్ప్లిసిట్ స్టైల్కు మారడం లేదు; మీరు కేవలం ప్రతి మాడ్యూల్ యొక్క సరిహద్దు వద్ద ఒప్పందాన్ని (contract) అధికారికం చేస్తున్నారు.
ఇది మీ కోడ్బేస్కు సరిపోతుందా?
isolatedDeclarationsని స్వీకరించడం వల్ల మీరు మీ సమయాన్ని ఎక్కడ గడుపుతారనేది మారుతుంది. మీరు ఒక ఎక్స్పోర్ట్ను రాసేటప్పుడు కొన్ని అదనపు కీస్ట్రోక్స్ (keystrokes) కేటాయిస్తారు, దానికి బదులుగా ప్రతి బిల్డ్లో అయ్యే అదనపు సమయాన్ని మీరు ఆదా చేయవచ్చు. లైబ్రరీ రచయితలకు (library authors), ఇది తరచుగా సులభమైన నిర్ణయం. పబ్లిక్ APIలకు ఎలాగూ అనోటేషన్లు ఉండాలి. క్లోజ్డ్ మోనోరెపో (closed monorepo)లో పనిచేసే అప్లికేషన్ డెవలపర్లకు, ఈ ప్రారంభ ఖర్చు అనవసరమైన పనిలా అనిపించవచ్చు. కానీ మీ బృందం బిల్డ్ సమయాన్ని కాఫీ బ్రేక్లతో పోల్చి చూస్తే, ఈ మార్పు త్వరగా ఆకర్షణీయంగా మారుతుంది.
మీరు దీనిని క్రమంగా (incrementally) స్వీకరించవచ్చు. ఫ్లాగ్ను ఎనేబుల్ చేసి, కంపైలర్ను రన్ చేయండి, మరియు ఎక్స్పోర్ట్ చేయబడిన సింబల్స్పై అది చూపే లోపాలను (errors) సరిదిద్దండి. ఏ పబ్లిక్-ఫేసింగ్ టైపులు ఇంప్లిసిట్గా ఉన్నాయో ఎర్రర్ మెసేజ్లు మీకు ఖచ్చితంగా చెబుతాయి. వాటిని సరిదిద్దండి, అంతర్గత అంశాలను అలాగే వదిలేయండి, మరియు మీ డిక్లరేషన్ ప్రక్రియ ఎంత వేగవంతం అవుతుందో చూడండి.
ఒక విషయం గుర్తుంచుకోవాలి: ఈ ఫ్లాగ్ TypeScript యొక్క టైప్ చెకర్ (type checker)ను వేగవంతం చేయదు. మీ ఎడిటర్లో వేగవంతమైన ఫీడ్బ్యాక్ లేదా వేగవంతమైన tsc --noEmit రన్లు కావాలనుకుంటే, మీకు ఇంకా ప్రాజెక్ట్ రిఫరెన్స్లు (project references), కఠినమైన ఫైల్ ఇన్క్లూజన్ లేదా ఇతర ఆర్కిటెక్చరల్ పరిష్కారాలు అవసరమవుతాయి. isolatedDeclarations ప్రత్యేకంగా .d.ts ఫైళ్ల ఎమిషన్ను (emission) లక్ష్యంగా చేసుకుంటుంది. ఇది ఒక బిల్డ్ ఆప్టిమైజేషన్ (build optimization), టైప్-చెకింగ్ ఆప్టిమైజేషన్ కాదు.
అసలు సారాంశం
isolatedDeclarations మీ పబ్లిక్ టైపులను ఫస్ట్-క్లాస్ ఆర్టిఫాక్ట్లుగా (first-class artifacts) పరిగణించాలని కోరుతుంది. కంపైలర్ను వాటిని ఊహించమని (deduce) వదిలేయండి. వాటిని స్పష్టంగా రాయండి. మీరు అలా చేసిన తర్వాత, కంపైలర్ ప్రతిసారీ డిక్లరేషన్ ఫైల్ను రూపొందించడానికి మీ పూర్తి డిపెండెన్సీ గ్రాఫ్ను వెతకడం ఆపివేస్తుంది. ఇది సమాంతరంగా (in parallel) ఎమిట్ చేస్తుంది, esbuild మరియు swc వంటి సాధనాలు పూర్తి TypeScript వర్క్ఫ్లోలను నిర్వహిస్తాయి, మరియు మీ మోనోరెపో బిల్డ్లు నెమ్మదించడం ఆగిపోతాయి.
దీని వల్ల అయ్యే ఖర్చు బిల్డ్ సమయం నుండి కోడ్ రాసే సమయానికి మారుతుంది. ఎదుగుతున్న చాలా బృందాలకు, ఇది లాభదాయకమైన మార్పిడి.
