A Decorator is a special kind of declaration that can be applied to classes, methods, accessor, property, or parameter. Decorators are simply functions that are prefixed @expression symbol, where expression must evaluate to a function that will be called at runtime with information about the decorated declaration.
To enable experimental support for decorators, we must enable the experimentalDecorators compiler option either on the command line or in our tsconfig.json:
$tsc --target ES5 --experimentalDecorators
tsconfig.json
{ "compilerOptions": { "target": "ES5", "experimentalDecorators": true } }
TypeScript Decorators serves the purpose of adding both annotations and metadata to the existing code in a declarative way.
To customize decorator how it is applied to a declaration, we can write a decorator factory. A decorator factory is a function which returns the expression that will be called by the decorator at runtime.
A decorator factory can be written in the following manner:
function color(value: string) { // this is the decorator factory return function (target) { // this is the decorator // do something with 'target' and 'value'... } }
We can apply multiple decorators to a declaration. The following examples help to understand it.
@f @g x
@f @g x
TypeScript uses the following types of Decorators:
A class decorator is defined just before the class declaration, and it tells about the class behaviors. A class decorator is applied to the constructor of the class. A class decorator can be used to observe, modify, or replace a class definition. If the class decorator returns a value, it will replace the class declaration with the given constructor function.
@sealed class Person { msg: string; constructor(message: string) { this.msg = message; } show() { return "Hello, " + this.msg; } }
In the above example, when @sealed decorator is executed, it will seal both the constructor and its prototype so that we cannot inherit the Person class.
A Method Decorator is defined just before a method declaration. It is applied to a property descriptor for the method. It can be used to observe, modify, or replace a method definition. We cannot use method decorator in a declaration file.
The expression for the method decorator function accepts three arguments. They are:
In the below example, the @log decorator will log the new item entry.
class Item { itemArr: Array; constructor() { this.itemArr = []; } @log Add(item: string): void { this.itemArr.push(item); } GetAll(): Array { return this.itemArr; } }
An Accessor Decorator is defined just before an accessor declaration. It is applied to the property descriptor for the accessor. It can be used to observe, modify, or replace an accessor's definitions.
The expression for the accessor decorator function accepts three arguments. They are:
In the below example, an accessor decorator (@configurable) is applied to a member of the Employee class.
class Employee { private _salary: number; private _name: string; @configurable(false) get salary() { return 'Rs. ${this._salary}'; } set salary(salary: any) { this._salary = +salary; } @configurable(true) get name() { return 'Sir/Madam, ${this._name}'; } set name(name: string) { this._name = name; } }
A property decorator is defined just before a property declaration. It is similar to the method decorators. The only difference between property decorators and method decorators is that they do not accept property descriptor as an argument and do not return anything.
The expression for the property decorator function accepts two arguments. They are:
In the below example, the @ReadOnly decorator will make the name property as read-only, so we can't change its value.
class Company { @ReadOnly name: string = "rookienerd.com"; } let comp = new Company(); comp.name = 'SSSIT.com'; // Here, we can't change company name. console.log(comp.name); // 'rookienerd.com'
A parameter decorator is defined just before a parameter declaration. It is applied to the function for a class constructor or method declaration. It cannot be used in a declaration file or in any other ambient context (such as in a declared class).
The expression for the parameter decorator function accepts three arguments. They are:
In the below example, a parameter decorator (@required) is applied to the parameter of a member of the Person class.
class Person { msg: string; constructor(message: string) { this.msg = message; } @validate show(@required name: string) { return "Hello " + name + ", " + this.msg; } }