Ce face experimentalDecorators
Decoratorii (@jurnal pus deasupra unei metode) există în TypeScript în două variante. Varianta veche, experimentală, folosită de Angular, NestJS și TypeORM, primește (tinta, nume, descriptor). Varianta standard ECMAScript (TypeScript 5.0+) primește (valoare, context). Fără opțiune, TypeScript folosește decoratorii standard. Cu experimentalDecorators, folosește varianta veche.
emitDecoratorMetadata funcționează doar cu varianta veche (altfel TS5052): adaugă în JavaScript informații despre tipuri (design:type, design:paramtypes), citite la rulare cu biblioteca reflect-metadata. Așa face NestJS injecția de dependențe. Ambele opțiuni sunt implicit false.
Pentru cod nou, fără un framework care le cere, folosește decoratorii standard și lasă opțiunea oprită.
Parametri
| Parametru | Descriere |
|---|---|
experimentalDecorators: true |
Decoratorii vechi, cu (tinta, nume, descriptor). |
emitDecoratorMetadata: true |
Se scriu metadate despre tipuri pentru reflect-metadata. |
Exemple
Exemplul 1: Decorator standard (fără opțiune)
Decoratorul primește metoda și un obiect context. tsc îl transformă în cod care rulează în Node.js. Exemplul rulează așa cum este.
function jurnal(metoda: Function, context: ClassMethodDecoratorContext) {
return function (this: unknown, ...args: unknown[]) {
console.log(`apel ${String(context.name)}(${args.join(", ")})`);
return metoda.apply(this, args);
};
}
class Cos {
@jurnal
adauga(produs: string, pret: number) {
return `${produs}: ${pret} lei`;
}
}
console.log(new Cos().adauga("pâine", 5));
Rezultat
apel adauga(pâine, 5)
pâine: 5 lei
Exemplul 2: Decorator vechi cu experimentalDecorators
Același efect, scris în stilul vechi. Fără opțiune, tsc îl refuză: decoratorul standard primește doar două argumente.
// tsconfig.json
{
"compilerOptions": {
"target": "es2022",
"module": "nodenext",
"experimentalDecorators": true
}
}
// index.ts
function jurnal(_tinta: object, nume: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function (this: unknown, ...args: unknown[]) {
console.log(`apel ${nume}(${args.join(", ")})`);
return original.apply(this, args);
};
}
class Cos {
@jurnal
adauga(produs: string, pret: number) {
return `${produs}: ${pret} lei`;
}
}
console.log(new Cos().adauga("pâine", 5));
Rezultat (tsc 5.9)
$ npx tsc && node index.js
apel adauga(pâine, 5)
pâine: 5 lei
$ npx tsc --experimentalDecorators false --noEmit
index.ts(10,3): error TS1241: Unable to resolve signature of method decorator when called as an expression.
The runtime will invoke the decorator with 2 arguments, but the decorator expects 3.
Exemplul 3: Metadatele de tip
Cu emitDecoratorMetadata, fiecare câmp decorat primește __metadata("design:type", ...) cu tipul lui din TypeScript.
// tsconfig.json
{
"compilerOptions": {
"target": "es2022",
"module": "nodenext",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
// index.ts
function camp(_t: object, _n: string) {}
class Produs {
@camp nume: string = "";
@camp pret: number = 0;
}
console.log(new Produs());
Rezultat (tsc 5.9)
$ npx tsc && sed -n '10,22p' index.js
function camp(_t, _n) { }
class Produs {
nume = "";
pret = 0;
}
__decorate([
camp,
__metadata("design:type", String)
], Produs.prototype, "nume", void 0);
__decorate([
camp,
__metadata("design:type", Number)
], Produs.prototype, "pret", void 0);
Greșeli frecvente
- Să copiezi un decorator scris pentru Angular/NestJS într-un proiect fără
experimentalDecorators. Semnătura este diferită și apare TS1241. - Să pornești
emitDecoratorMetadatafărăexperimentalDecorators: eroarea TS5052.
Comenzi înrudite
useDefineForClassFields: Câmpurile de clasă se comportă ca în standardul JavaScript (definite cu Object.defineProperty), nu ca atribuiri în constructor.target: Versiunea de JavaScript generată: sintaxa mai nouă decât ținta este transformată în cod echivalent mai vechi.importHelpers: Ia funcțiile ajutătoare (__awaiter, __decorate…) din pachetul tslib, în loc să le copieze în fiecare fișier.