Învață programare
TypeScript pentru începători
Înveți să adaugi tipuri la JavaScript ca să prinzi greșelile înainte să ruleze programul.
TypeScript este JavaScript la care adaugi „etichete” numite tipuri. Eticheta spune ce fel de valoare așteaptă fiecare variabilă sau funcție: un număr, un text, un jucător. Dacă încerci să pui altceva, editorul te avertizează imediat, înainte să rulezi programul.
Presupunem că știi bazele JavaScript: variabile, funcții, liste și obiecte. Dacă nu, începe cu tutorialul de JavaScript și revino aici.
De ce tipuri?
În JavaScript poți apela o funcție cu orice, iar greșeala apare abia când programul rulează, uneori într-un moment prost. Imaginează-ți o funcție care calculează nivelul din XP și cineva îi dă textul „abc” în loc de număr. Cu TypeScript, greșeala se vede în editor, subliniată cu roșu, înainte să ajungă la utilizatori.
Bonus: editorul te ajută cu sugestii. Când scrii un punct după un jucător, îți arată ce proprietăți are. Tipurile sunt și documentație care nu se învechește.
Cum rulezi un fișier TypeScript
Fișierele TypeScript au extensia .ts. Versiunile recente de Node.js (aici folosim Node.js 24) pot rula direct un fișier .ts: elimină tipurile și rulează restul ca JavaScript. Verificarea propriu-zisă a tipurilor o face compilatorul TypeScript, iar tu o rulezi separat.
node jucator.ts
npm install --save-dev typescript
npx tsc --noEmit
- node jucator.ts rulează fișierul. Node.js nu verifică tipurile, doar le ignoră.
- npm install --save-dev typescript adaugă compilatorul în proiectul tău (o singură dată, din folderul proiectului).
- npx tsc --noEmit verifică tipurile în tot proiectul și afișează erorile, fără să creeze fișiere noi.
Node.js elimină doar tipurile simple. Construcțiile care generează cod, cum sunt enum și namespace, nu funcționează cu această metodă. În tutorial le evităm; în tsconfig.json există opțiunea erasableSyntaxOnly care te avertizează dacă le folosești.
Adnotări de tip
Pui tipul după nume, separat prin două puncte. Tipurile de bază sunt string, number și boolean. De multe ori nu trebuie să scrii tipul: TypeScript îl deduce din valoarea pusă, de exemplu const x = 5 este deja un number.
const nume: string = 'Alex';
let nivel: number = 3;
const activ: boolean = true;
nivel = nivel + 1;
console.log(`${nume} - nivel ${nivel} - activ: ${activ}`);
Rezultat
Alex - nivel 4 - activ: trueCea mai utilă adnotare este la funcții: tipurile parametrilor și tipul rezultatului, după paranteze.
function aduna(a: number, b: number): number {
return a + b;
}
const salut = (nume: string): string => `Salut, ${nume}!`;
console.log(aduna(2, 3));
console.log(salut('Dana'));
Rezultat
5
Salut, Dana!Interface și type
Pentru obiecte descrii forma lor cu interface sau cu type. Ambele fac aproape același lucru; alege una și fii consecvent. Un semn de întrebare după numele proprietății o face opțională, adică poate lipsi.
interface Jucator {
nume: string;
nivel: number;
clan?: string;
}
type Arma = { nume: string; damage: number };
const j: Jucator = { nume: 'Ioana', nivel: 5 };
const a: Arma = { nume: 'sabie', damage: 12 };
console.log(j.nume, j.nivel, j.clan ?? 'fără clan');
console.log(a.nume, a.damage);
Rezultat
Ioana 5 fără clan
sabie 12Operatorul ?? dă o valoare de rezervă când ce e în stânga este null sau undefined. Aici clan lipsește, deci primim „fără clan”.
Uniuni, valori literale și narrowing
Cu bara verticală spui „unul dintre aceste tipuri”. Poți lista chiar valori exacte: un tip care acceptă doar trei texte anume. Dacă scrii altceva, editorul te oprește. E ideal pentru roluri, stări sau comenzi.
type Rol = 'membru' | 'moderator' | 'admin';
function eticheta(rol: Rol): string {
if (rol === 'admin') return 'Administrator';
if (rol === 'moderator') return 'Moderator';
return 'Membru';
}
console.log(eticheta('admin'), eticheta('membru'));
let id: number | string = 42;
console.log(id);
id = 'abc-1';
console.log(id);
Rezultat
Administrator Membru
42
abc-1Când o valoare poate fi de mai multe tipuri, trebuie să verifici ce este înainte s-o folosești. După verificare, TypeScript știe tipul exact în acel bloc. Se numește narrowing.
function formateaza(valoare: number | string): string {
if (typeof valoare === 'number') {
return valoare.toFixed(1);
}
return valoare.toUpperCase();
}
console.log(formateaza(3), formateaza('xp'));
Rezultat
3.0 XPÎn ramura cu typeof, valoare este sigur number, deci toFixed există. În afara ei este sigur string, deci toUpperCase există. Fără verificare, editorul ar semnala eroare.
Generice, pe scurt
Un generic este un tip „cu loc liber”, notat de obicei T. Funcția rămâne aceeași, indiferent de tipul datelor, iar TypeScript păstrează informația. Ca o cutie pe care scrie „conține T”: poate fi cutie de numere sau de texte, dar știi mereu ce scoți din ea.
function primul<T>(lista: T[]): T | undefined {
return lista[0];
}
console.log(primul([10, 20, 30]));
console.log(primul(['a', 'b']));
console.log(primul([]));
type Rezultat<T> = { ok: true; valoare: T } | { ok: false; eroare: string };
function imparte(a: number, b: number): Rezultat<number> {
if (b === 0) return { ok: false, eroare: 'împărțire la zero' };
return { ok: true, valoare: a / b };
}
const r1 = imparte(10, 4);
console.log(r1.ok ? r1.valoare : r1.eroare);
const r2 = imparte(1, 0);
console.log(r2.ok ? r2.valoare : r2.eroare);
Rezultat
10
a
undefined
2.5
împărțire la zeroProiect mic: rangul jucătorilor
Reluăm ideea din tutorialul de JavaScript, de data asta cu tipuri. Regula este doar un exemplu: 100 XP pentru fiecare nivel, iar rangul depinde de nivel.
interface Jucator {
nume: string;
xp: number;
}
type Rang = 'Începător' | 'Avansat' | 'Veteran';
function nivelDinXp(xp: number): number {
return Math.floor(xp / 100) + 1;
}
function rangPentru(nivel: number): Rang {
if (nivel >= 10) return 'Veteran';
if (nivel >= 3) return 'Avansat';
return 'Începător';
}
function descrie(j: Jucator): string {
const nivel = nivelDinXp(j.xp);
return `${j.nume}: nivel ${nivel} (${rangPentru(nivel)})`;
}
const jucatori: Jucator[] = [
{ nume: 'Ana', xp: 50 },
{ nume: 'Bogdan', xp: 250 },
{ nume: 'Carmen', xp: 999 },
];
for (const j of jucatori) {
console.log(descrie(j));
}
const clasament = [...jucatori].sort((a, b) => b.xp - a.xp).map((j) => j.nume);
console.log(clasament.join(' > '));
Rezultat
Ana: nivel 1 (Începător)
Bogdan: nivel 3 (Avansat)
Carmen: nivel 10 (Veteran)
Carmen > Bogdan > AnaErorile de tip arată intimidant la început, dar se citesc simplu: ce ai dat, ce se aștepta. Câteva dintre cele mai des întâlnite, cu sensul lor:
function dubleaza(x: number): number {
return x * 2;
}
dubleaza('5');
// Argument of type 'string' is not assignable to parameter of type 'number'.
const nivel: number = 'trei';
// Type 'string' is not assignable to type 'number'.
const jucator = { nume: 'Ana' };
console.log(jucator.xp);
// Property 'xp' does not exist on type '{ nume: string; }'.
- Prima eroare: ai dat un text acolo unde funcția vrea număr. Convertește valoarea sau corectează apelul.
- A doua: ai pus în variabilă o valoare de alt tip decât cel declarat.
- A treia: ai cerut o proprietate care nu există în obiect, de obicei o greșeală de scris sau un câmp uitat.
- Mesajele cu „possibly undefined” înseamnă că valoarea poate lipsi. Verifică-o cu if sau folosește ?? ca să dai o valoare de rezervă.
Evită tipul any. Înseamnă „oprește verificarea aici” și anulează tocmai ce te ajută TypeScript. Dacă nu știi tipul, încearcă unknown și verifică valoarea înainte să o folosești.
Unde se folosește în DominosLand
În proiectul DominosLand, API-ul este scris în TypeScript cu NestJS (serviciul api), iar site-ul și panoul sunt scrise în TypeScript cu Next.js și React (aplicația web). Launcher-ul de pe Windows folosește TypeScript cu Electron. Tipurile ajută mai ales acolo unde multe fișiere trebuie să se înțeleagă între ele: aceeași formă de date apare în mai multe locuri, iar compilatorul te avertizează dacă ai schimbat-o într-un loc și ai uitat în altul.