Ts Decorators
Decorators are an experimental feature in TypeScript.\\\\n\\\\nIt allows developers to add extra functionality to classes, methods, properties, or parameters without modifying the original class.\\\\n\\\\nA decorator is essentially a function that can be called at runtime to modify the behavior of the target object.\\\\n\\\\n* * *\\\\n\\\\n## Decorator Introduction\\\\n\\\\nDecorators use the `@` symbol as syntactic sugar and can be attached to classes, methods, accessors, properties, or parameters.\\\\n\\\\nThis pattern is commonly used in framework development; for example, Angular and TypeORM heavily use decorators to implement features like dependency injection and data validation.\\\\n\\\\n> **Note:** Decorators are currently an experimental feature and need to be explicitly enabled in tsconfig.json. When using them in a production environment, please confirm the level of support for experimental features in your project.\\\\n\\\\n* * *\\\\n\\\\n## Configuring and Enabling Decorators\\\\n\\\\nBefore using decorators, you need to enable the relevant compilation options in the TypeScript configuration file tsconfig.json.\\\\n\\\\n## tsconfig.json Configuration\\\\n\\\\n{\\\\n\\\\n"compilerOptions":{\\\\n\\\\n// Enable decorator syntax\\\\n\\\\n"experimentalDecorators":true,\\\\n\\\\n// Enable decorator metadata (used for dependency injection frameworks)\\\\n\\\\n"emitDecoratorMetadata":true\\\\n\\\\n}\\\\n\\\\n}\\\\n\\\\n**Parameter Description:**\\\\n\\\\n* **experimentalDecorators:** Enables decorator syntax support, which is a prerequisite for using decorators\\\\n* **emitDecoratorMetadata:** Generates decorator metadata in the compiled JavaScript, for use by dependency injection frameworks\\\\n\\\\n* * *\\\\n\\\\n## Class Decorators\\\\n\\\\nClass decorators are applied to the constructor of a class and can modify the class definition or add additional processing logic.\\\\n\\\\nA class decorator receives one parameter, which is the constructor of the target class.\\\\n\\\\n## Basic Usage of Class Decorators\\\\n\\\\n// Define a class decorator function\\\\n\\\\n// The parameter target is the decorated class constructor\\\\n\\\\nfunction sealed(target:Function){\\\\n\\\\n// Print the name of the class the decorator is applied to\\\\n\\\\n console.log("Decorators applied to: "+ target.name);\\\\n\\\\n// Use Object.seal to lock the constructor and prototype\\\\n\\\\n// Prevent adding or deleting properties at runtime\\\\n\\\\nObject.seal(target);\\\\n\\\\nObject.seal(target.prototype);\\\\n\\\\n}\\\\n\\\\n// Apply the decorator to the class using @ syntax\\\\n\\\\n@sealed\\\\n\\\\nclass Person {\\\\n\\\\n name: string;\\\\n\\\\nconstructor(name: string){\\\\n\\\\nthis.name= name;\\\\n\\\\n}\\\\n\\\\n}\\\\n\\\\n// Create an instance for testing\\\\n\\\\nvar person =new Person("TUTORIAL");\\\\n\\\\n console.log("create: "+ person.name);\\\\n\\\\n// Try to add a new property (will be prevented because the class is sealed)\\\\n\\\\n// person.age = 25; // Fails silently\\\\n\\\\n**Execution Result:**\\\\n\\\\nDecorators applied to: Personcreate: TUTORIAL\\\\n**Explanation:**\\\\n\\\\nClass decorators execute when the class is defined, and are typically used to modify class behavior, add metadata, or implement AOP (Aspect-Oriented Programming).\\\\n\\\\n* * *\\\\n\\\\n## Method Decorators\\\\n\\\\nMethod decorators are applied to class methods and can modify the method's Property Descriptor.\\\\n\\\\nA method decorator receives three parameters: the target object, the property name, and the property descriptor.\\\\n\\\\n## Basic Usage of Method Decorators\\\\n\\\\n// Define a method decorator factory\\\\n\\\\n// Returns a decorator function\\\\n\\\\nfunction enumerable(value:boolean){\\\\n\\\\n// Returns the decorator function, receiving three parameters\\\\n\\\\nreturn function(\\\\n\\\\n target: any,// The prototype object of the owning class\\\\n\\\\n propertyKey: string,// The method name\\\\n\\\\n descriptor: PropertyDescriptor // The property descriptor\\\\n\\\\n){\\\\n\\\\n// Modify the enumerable characteristic of the property\\\\n\\\\n// false means the method is not enumerable\\\\n\\\\n descriptor.enumerable= value;\\\\n\\\\n};\\\\n\\\\n}\\\\n\\\\nclass Greeter {\\\\n\\\\n greeting: string;\\\\n\\\\nconstructor(message: string){\\\\n\\\\nthis.greeting= message;\\\\n\\\\n}\\\\n\\\\n// Apply the decorator, setting the method as non-enumerable\\\\n\\\\n@enumerable(false)\\\\n\\\\n greet(){\\\\n\\\\nreturn"Hello, "+this.greeting;\\\\n\\\\n}\\\\n\\\\n}\\\\n\\\\nvar g =new Greeter("World");\\\\n\\\\n// Check if the greet method is enumerable\\\\n\\\\n console.log("Method Enumerable: "+ g.propertyIsEnumerable("greet"));\\\\n\\\\n// Iterate over the object's properties\\\\n\\\\nfor(var key in g){\\\\n\\\\n console.log("property: "+ key);\\\\n\\\\n}\\\\n\\\\n**Execution Result:**\\\\n\\\\nMethod Enumerable: false\\\\n> **Tip:** PropertyDescriptor contains properties like enumerable, configurable, writable, and value, which can be modified as needed.\\\\n\\\\n* * *\\\\n\\\\n## Accessor Decorators\\\\n\\\\nAccessor decorators are applied to the getter and setter methods of a class.\\\\n\\\\nSimilar to method decorators, accessor decorators can also modify the property descriptor.\\\\n\\\\n## Accessor Decorator Usage\\\\n\\\\n// Accessor decorator factory\\\\n\\\\nfunction configurable(value:boolean){\\\\n\\\\nreturn function(\\\\n\\\\n target: any,\\\\n\\\\n propertyKey: string,\\\\n\\\\n descriptor: PropertyDescriptor\\\\n\\\\n){\\\\n\\\\n// Modify the configurable characteristic of the property\\\\n\\\\n// false means the accessor cannot be reconfigured or deleted\\\\n\\\\n descriptor.configurable= value;\\\\n\\\\n};\\\\n\\\\n}\\\\n\\\\nclass Point {\\\\n\\\\n private _x: number =0;\\\\n\\\\n private _y: number =0;\\\\n\\\\n// Use the decorator to lock the getter\\\\n\\\\n@configurable(false)\\\\n\\\\nget x(){\\\\n\\\\nreturn this._x;\\\\n\\\\n}\\\\n\\\\n@configurable(false)\\\\n\\\\nget y(){\\\\n\\\\nreturn this._y;\\\\n\\\\n}\\\\n\\\\nset x(value: number){\\\\n\\\\nthis._x = value;\\\\n\\\\n}\\\\n\\\\nset y(value: number){\\\\n\\\\nthis._y = value;\\\\n\\\\n}\\\\n\\\\n}\\\\n\\\\nvar point =new Point();\\\\n\\\\n point.x=10;\\\\n\\\\n point.y=20;\\\\n\\\\n console.log("Coordinates: ("+ point.x+", "+ point.y+")");\\\\n\\\\n**Explanation:**\\\\n\\\\nAccessor decorators cannot be applied to both the getter and setter of the same property simultaneously; you must choose only one.\\\\n\\\\n* * *\\\\n\\\\n## Property Decorators\\\\n\\\\nProperty decorators are applied to the property definition of a class.\\\\n\\\\nA property decorator receives two parameters: the target object and the property name.\\\\n\\\\n## Property Decorator Usage\\\\n\\\\n// Property decorator factory\\\\n\\\\nfunction format(formatString: string){\\\\n\\\\nreturn function(\\\\n\\\\n target: any,// The prototype object of the class\\\\n\\\\n propertyKey: string // The property name\\\\n\\\\n){\\\\n\\\\n// Store metadata on the target object\\\\n\\\\n// Use propertyKey + "_format" as the key name to avoid conflicts\\\\n\\\\nObject.defineProperty(target, propertyKey +"_format",{\\\\n\\\\n value: formatString,\\\\n\\\\n writable:false,\\\\n\\\\n enumerable:false,\\\\n\\\\n configurable:true\\\\n\\\\n});\\\\n\\\\n};\\\\n\\\\n}\\\\n\\\\nclass User {\\\\n\\\\n// Apply the property decorator, specifying the date format\\\\n\\\\n@format("YYYY-MM-DD")\\\\n\\\\n birthDate: string;\\\\n\\\\nconstructor(birthDate: string){\\\\n\\\\nthis.birthDate= birthDate;\\\\n\\\\n}\\\\n\\\\n}\\\\n\\\\nvar user =new User("1990-01-01");\\\\n\\\\n console.log("Birth Date: "+ user.birthDate);\\\\n\\\\n// Access the stored metadata\\\\n\\\\n console.log("Date Format: "+(user as any).birthDate_format);\\\\n\\\\n**Execution Result:**\\\\n\\\\nBirth Date: 1990-01-01Date Format: YYYY-MM-DD\\\\n\\\\n* * *\\\\n\\\\n## Parameter Decorators\\\\n\\\\nParameter decorators are applied to the parameters of class methods and can add metadata or markers to the parameters.\\\\n\\\\nA parameter decorator receives three parameters: the target object, the method name, and the index of the parameter in the function.\\\\n\\\\n## Parameter Decorator Usage\\\\n\\\\n// Parameter decorator\\\\n\\\\n// Used to record parameter information or perform validation\\\\n\\\\nfunction logParameter(\\\\n\\\\n target: any,// The prototype object of the class\\\\n\\\\n propertyKey: string,// The method name\\\\n\\\\n parameterIndex: number // The index position of the parameter in the function (starting from 0)\\\\n\\\\n){\\\\n\\\\n console.log("Parameter Decorators: "+ propertyKey +\\\\n\\\\n" Line "+(parameterIndex +1)+" Parameters");\\\\n\\\\n}\\\\n\\\\nclass Greeter {\\\\n\\\\n greeting: string;\\\\n\\\\nconstructor(greeting: string){\\\\n\\\\nthis.greeting= greeting;\\\\n\\\\n}\\\\n\\\\n// Apply the decorator using @ syntax before the parameter\\\\n\\\\n greet(@logParameter name: string){\\\\n\\\\nreturn this.greeting+", "+ name;\\\\n\\\\n}\\\\n\\\\n}\\\\n\\\\nvar greeter =new Greeter("Hello");\\\\n\\\\n greeter.greet("TUTORIAL");\\\\n\\\\n**Execution Result:**\\\\n\\\\nParameter Decorators: greet Line 1 Parameters\\\\n\\\\n* * *\\\\n\\\\n## Decorator Factories\\\\n\\\\nDecorator factories are functions that return decorator functions.\\\\n\\\\nThrough decorator factories, you can pass custom parameters when applying decorators, achieving more flexible configuration.\\\\n\\\\n## Decorator Factory Implementation: Colored Logs\\\\n\\\\n// Decorator factory: receives configuration parameters, returns a decorator function\\\\n\\\\nfunction color(colorCode: string){\\\\n\\\\n// colorCode is the ANSI escape sequence color code\\\\n\\\\n// For example: 34 = blue, 31 = red, 32 = green\\\\n\\\\nreturn function(\\\\n\\\\n target: any,\\\\n\\\\n propertyKey: string,\\\\n\\\\n descriptor: PropertyDescriptor\\\\n\\\\n){\\\\n\\\\n// Save the original method\\\\n\\\\nvar originalMethod = descriptor.value;\\\\n\\\\n// Override the method, adding color\\\\n\\\\n descriptor.value=function(...args: any[]){\\\\n\\\\n// Call the original method to get the return value\\\\n\\\\nvar result = originalMethod.apply(this, args);\\\\n\\\\n// If in a terminal environment, add color to the output\\\\n\\\\n// ANSI escape sequence format: \\\\\\\\x1bm content \\\\\\\\x1b[0m\\\\n\\\\nreturn"\\\\\\\\x 1b["+ colorCode +"m"+ result +"\\\\\\\\x 1b[0m";\\\\n\\\\n};\\\\n\\\\n};\\\\n\\\\n}\\\\n\\\\nclass Logger {\\\\n\\\\n// Use the decorator factory, passing the blue code 34\\\\n\\\\n@color("34")\\\\n\\\\n log(message: string): string {\\\\n\\\\nreturn message;\\\\n\\\\n}\\\\n\\\\n@color("31")\\\\n\\\\n error(message: string): string {\\\\n\\\\nreturn message;\\\\n\\\\n}\\\\n\\\\n@color("32")\\\\n\\\\n success(message: string): string {\\\\n\\\\nreturn message;\\\\n\\\\n}\\\\n\\\\n}\\\\n\\\\nvar logger =new Logger();\\\\n\\\\n console.log(logger.log("This is a blue log"));\\\\n\\\\n console.log(logger.error("This is a red error"));\\\\n\\\\n console.log(logger.success("This is a green success"));\\\\n\\\\n**Execution Result:**\\\\n\\\\nThis is a blue log (displayed in blue in the terminal) This is a red error (displayed in red in the terminal) This is a green success (displayed in green in the terminal)\\\\n> **Explanation:** Decorator factories are the most commonly used form in actual development, as they allow passing parameters when applying decorators, achieving configurability.\\\\n\\\\n* * *\\\\n\\\\n## Decorator Execution Order\\\\n\\\\nWhen there are multiple decorators on a class, the execution order follows specific rules.\\\\n\\\\n* Decorators are applied from bottom to top\\\\n* Multiple decorators of the same type execute from right to left\\\\n* Parameter decorators execute before method decorators\\\\n\\\\n## Decorator Execution Order Example\\\\n\\\\n// Multiple decorators stacked together\\\\n\\\\nfunction first(){\\\\n\\\\n console.log("first Decorators");\\\\n\\\\nreturn function(target: any){\\\\n\\\\n console.log("first Decoratorsfunction");\\\\n\\\\n};
YouTip