Ghid de migrare la TypeScript
Mutarea unui proiect JavaScript la TypeScript face codul mai ușor de întreținut și îți oferă o experiență de editare mult mai bună.
Acest ghid te conduce pas cu pas prin migrare.
Etapa de pregătire
Evaluează baza de cod. Înainte de a începe migrarea:
- Stabilește dimensiunea și complexitatea bazei de cod
- Documentează procesul de construire și dependențele
- Caută definiții de tip existente (fișiere
.d.ts) - Identifică traseele critice care au nevoie de atenție suplimentară
Pregătește controlul versiunilor. Asigură-te că ai un depozit git curat (sau echivalent). Creează o ramură pentru migrare și înregistrează starea curentă, ca să poți oricând compara sau reveni:
git checkout -b typescript-migrationgit add .git commit -m "Pre-TypeScript migration state"
Configurare
Instalează TypeScript ca dependență de dezvoltare, împreună cu definițiile de tip pentru Node.js: npm install --save-dev typescript @types/node
Creează tsconfig.json. Pornește de la o configurație de bază în rădăcina proiectului:
"compilerOptions": {"target": "ES2020","module": "commonjs","strict": true,"esModuleInterop": true,"skipLibCheck": true,"forceConsistentCasingInFileNames": true,"outDir": "./dist","rootDir": "./src"},"include": ["src/**/*"],"exclude": ["node_modules"]
Notă: ajustează target la cel mai vechi mediu pe care trebuie să îl susții.
Abordări de migrare
Există două moduri de a migra.
Migrare graduală. Convertește câte un fișier pe rând, în timp ce restul rămâne JavaScript. Activează "allowJs": true și "checkJs": true în compilerOptions, astfel încât compilatorul să accepte și să verifice fișierele .js alături de fișierele .ts. Cea mai bună variantă pentru baze de cod mari, unde vrei perturbări minime.
Migrare dintr-o dată. Redenumește fiecare fișier .js în .ts și corectează erorile, de exemplu cu find src -name "*.js" -exec sh -c 'mv "$0" "${0%.js}.ts"' {} \;. Cea mai bună variantă pentru proiecte mici și medii și pentru proiecte noi (greenfield).
Notă: pentru proiectele mari este recomandată cu tărie abordarea graduală — menține perturbările reduse și volumul de muncă ușor de gestionat.
Migrare pas cu pas
1. Începe cu configurarea. Creează un tsconfig.json cu aceste setări recomandate, care îi permit lui TypeScript să îți verifice codul JavaScript fără a genera încă fișiere:
"compilerOptions": {"target": "ES2020","module": "commonjs","strict": true,"esModuleInterop": true,"skipLibCheck": true,"forceConsistentCasingInFileNames": true,"outDir": "./dist","rootDir": "./src","allowJs": true,"checkJs": true,"noEmit": true},"include": ["src/**/*"],"exclude": ["node_modules", "dist"]
2. Activează verificarea de tip pentru JavaScript. Adaugă // @ts-check la începutul unui fișier JavaScript și TypeScript începe să îl verifice (vezi primul fragment). Poți reduce la tăcere o singură linie cu // @ts-ignore.
3. Redenumește fișierele în .ts. Începe cu fișierele necritice. Redenumește un fișier cu mv src/utils/helpers.js src/utils/helpers.ts sau un director întreg (cu grijă) cu find src/utils -name "*.js" -exec sh -c 'mv "$0" "${0%.js}.ts"' {} \;.
4. Adaugă adnotări de tip. Dă treptat tipuri parametrilor, valorilor returnate și obiectelor (vezi al doilea fragment).
5. Actualizează scripturile de construire și de testare. Adaugă compilarea TypeScript în package.json: "scripts": { "build": "tsc", "dev": "tsc --watch", "test": "jest" }. Asigură-te că și configurația de teste poate rula fișiere TypeScript.
Verificarea de tip a unui fișier JavaScript
Cu // @ts-check și un tip JSDoc, atribuirea unui număr lui name este raportată ca eroare.
// @ts-check
/** @type {string} */
const name = 'John';
// TypeScript will catch this error
name = 42; // Error: Type '42' is not assignable to type 'string'
Adăugarea adnotărilor de tip
Aceeași funcție add înainte și după tipizare, plus o interfață folosită ca tip returnat.
// Before
function add(a, b) {
return a + b;
}
// After
function add(a: number, b: number): number {
return a + b;
}
// With interface
interface User {
id: number;
name: string;
email?: string;
}
function getUser(id: number): User {
return { id, name: 'John Doe' };
}
Unelte de migrare
Unele unelte pot face o parte din muncă în locul tău:
- ts-migrate — o unealtă automată de migrare de la JavaScript la TypeScript:
npx ts-migrate-full .(depozit GitHub) - TypeStat — convertește JavaScript în TypeScript cu siguranță de tip:
npx typestat(depozit GitHub) - pachetele @types — definiții de tip pentru dependențele tale, de exemplu
npm install --save-dev @types/react @types/node(caută-le pe TypeSearch)
Bune practici pentru migrarea la TypeScript
Începe cu pași mici și iterează
- Începe cu funcțiile utilitare și cu componentele care nu țin de interfața grafică
- Migrează câte un fișier sau un modul pe rând
- Înregistrează o comitere după fiecare pas reușit
Folosește facilitățile TypeScript — lasă inferența să lucreze acolo unde poate, folosește tipuri uniune pentru flexibilitate și gărzi de tip pentru verificări la execuție (vezi fragmentul).
Descurcă-te cu bibliotecile terțe
- Instalează pachetele
@typespentru dependențele tale - Scrie fișiere de declarații pentru bibliotecile care nu au tipuri
- Folosește
declare modulepentru extinderi globale de tip
Facilități utile din TypeScript
Inferența de tip, un alias de tip uniune și o funcție gardă de tip — trei facilități care fac codul migrat mai sigur cu efort minim.
// Use type inference where possible
const name = 'John'; // TypeScript infers 'string'
const age = 30; // TypeScript infers 'number'
// Use union types for flexibility
type Status = 'active' | 'inactive' | 'pending';
// Use type guards for runtime checks
function isString(value: any): value is string {
return typeof value === 'string';
}
Provocări frecvente și soluții
Proprietăți dinamice
Problemă: JavaScript folosește adesea obiecte simple pe post de dicționare, adăugând proprietăți mai târziu. TypeScript raportează că proprietatea nu există.
Soluție: folosește o semnătură de index sau o aserțiune de tip.
Gestionarea contextului this
Problemă: this se pierde în interiorul unei funcții callback obișnuite.
Soluție: folosește o funcție săgeată sau leagă explicit this.
Proprietăți dinamice: problema
Adăugarea proprietății name la un literal de obiect gol este o eroare, deoarece tipul lui nu are o astfel de proprietate.
// Before
const user = {};
user.name = 'John'; // Error: Property 'name' does not exist
Proprietăți dinamice: soluția
Fie o interfață cu o semnătură de index, fie o aserțiune de tip permite adăugarea proprietății.
// Option 1: Index signature
interface User {
[key: string]: any;
}
const user: User = {};
user.name = 'John'; // OK
// Option 2: Type assertion
const user = {} as { name: string };
user.name = 'John'; // OK
Contextul this: problema
În interiorul unui callback function obișnuit transmis lui setTimeout, this nu mai este instanța Counter.
class Counter {
count = 0;
increment() {
setTimeout(function() {
this.count++; // Error: 'this' is not defined
}, 1000);
}
}
Contextul this: soluția
O funcție săgeată păstrează this din contextul înconjurător; alternativ, tipizează this ca Counter și apelează .bind(this).
// Solution 1: Arrow function
setTimeout(() => {
this.count++; // 'this' is lexically scoped
}, 1000);
// Solution 2: Bind 'this'
setTimeout(function(this: Counter) {
this.count++;
}.bind(this), 1000);
Concluzie
Migrarea de la JavaScript la TypeScript este o investiție mare, dar care merită, în baza ta de cod. Cu acest ghid poți face schimbarea lin și treptat.
Idei principale:
- Începe cu un
tsconfig.jsonsolid - Folosește
allowJsșicheckJspentru o migrare graduală - Lasă sistemul de tipuri să prindă erorile devreme
- Actualizează procesul de construire și de testare ca să susțină TypeScript
- Rezolvă provocările frecvente cu tiparele arătate mai sus
Migrarea este un proces, nu un eveniment. O bază de cod mixtă în timpul tranziției este în regulă — contează progresul constant, păstrând calitatea codului ridicată.
Gata de început? Pregătește TypeScript în proiectul tău și adaugă treptat adnotări de tip; compilatorul te va îndruma către un cod mai robust. Pentru mai multe informații, vezi ghidul oficial de migrare TypeScript.