# How to use TypeScript decorators

TypeScript decorators offer an efficient and straightforward way to add extra functionality to objects without altering the original code. They can be applied to classes, methods, properties, accessors, and parameters, leveraging annotations and metadata.

## What are TypeScript decorators and what are they used for?

The principle of TypeScript decorators is not fundamentally new. Similar features can be found in other [programming languages](https://www.ionos.com/digitalguide/websites/web-development/which-programming-language-to-learn/), such as attributes in C#, [decorators in Python](https://www.ionos.com/digitalguide/websites/web-development/python-decorators/) or annotations in Java. This is a way of extending the **functionality of an object** without changing the source code. [TypeScript](https://www.ionos.com/digitalguide/websites/web-development/what-is-typescript/) has also been working with this approach for some time. Although most browsers do not (yet) support TypeScript decorators, it is still worth trying out this approach and its possibilities. Since version 5.0, the use of decorators has been massively simplified once again.

TypeScript decorators are used to add **annotations and additional metadata** for [TypeScript classes](https://www.ionos.com/digitalguide/websites/web-development/typescript-classes/) and elements. In addition to the classes, methods, properties, access methods and parameters can also be changed. The latter can be checked, and the values retrieved. This is also a major difference between TypeScript decorators and their equivalent for JavaScript.

## What is the syntax for decorators?

By adding TypeScript decorators to an object, you are essentially invoking a function that runs **without altering the source code**. This enhances functionality while maintaining clean and organized code. The basic syntax is as follows:

```typescript
@nameOfTheDecorator
```

You can create this function with either two or three parameters. The syntax for the function with three parameters looks like this:

```typescript
function decoratorFunction(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(`Decorating ${propertyKey} of class ${target.constructor.name}`);
}
class MyClass {
    @decoratorFunction
    myMethod() {
        console.log('Executing myMethod');
    }
}
```

The individual TypeScript decorators components are made up as follows:

- `target`: Refers to the object that the decorator is assigned to.
- `propertyKey`: This is a string representing the name of the class where the decorator is applied, which could be methods or properties.
- `descriptor`: Stores additional details about the object the decorator is applied to, such as properties like `value`, `writable`, `enumerable`, or `configurable`.

Here is the syntax of TypeScript decorators with two parameters:

```typescript
function decoratorFunction(target: any) {
    console.log(`Decorating ${target.name}`);
}
@decoratorFunction
class MyClass {
}
```

In this instance, decorators in TypeScript were used on a class.

## What are the various types of decorators?

We will explore different types of TypeScript decorators in detail, each with its own unique characteristics:

- Class decorators
- Method decorators
- Property decorators
- Accessor decorators
- Parameter decorators

## How to use TypeScript decorators for classes

If you want to customize the **properties of a class** and change its constructor, methods or properties, you can do so with TypeScript decorators. You receive the constructor as the first parameter as soon as you “decorate” the class with a function. This is an example of code where we are working with a customer list. It has some private and some public properties:

```typescript
class Customers {
    private static userType: string = "Generic";
    private _email: string;
    public customerName: string;
    public street: string = "";
    public residence: string = "";
    public country: string = "";
    constructor(customerName: string, email: string) {
        this.customerName = customerName;
        this._email = email;
    }
    static get userType() {
        return Customers.userType;
    }
    get email() {
        return this._email;
    }
    set email(newEmail: string) {
        this._email = newEmail;
    }
    address(): string {
        return `${this.street}\n${this.residence}\n${this.country}`;
    }
}
const p = new Customers("exampleCustomer", "name@example.com");
p.street = "325 Lafayette Rd";
p.residence = "New Jersey";
```

In the next step, we will incorporate TypeScript decorators to enhance functionality without retroactively modifying the source code. For the “Customer” class, we will apply the `@frozen` decorator, which prevents objects from being altered afterward. We will use `@required` for certain properties to mandate explicit input. Additionally, `@enumerable` will be used for enumerations, and `@deprecated` will indicate outdated inputs. Our first task will be to define these decorators:

```typescript
function frozen(constructor: Function) {
    Object.freeze(constructor);
    Object.freeze(constructor.prototype);
}
function required(target: any, propertyKey: string) {
    // Logic for required decorator
}
function enumerable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.enumerable = value;
    };
}
function deprecated(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.warn(`The method ${propertyKey} is deprecated.`);
}
```

After using TypeScript decorators, the final code looks like this:

```typescript
@frozen
class Customers {
    private static userType: string = "Generic";
    @required
    private _email: string;
    @required
    public customerName: string;
    public street: string = "";
    public residence: string = "";
    public country: string = "";
    constructor(customerName: string, email: string) {
        this.customerName = customerName;
        this._email = email;
    }
    @enumerable(false)
    get userType() {
        return Customers.userType;
    }
    get email() {
        return this._email;
    }
    set email(newEmail: string) {
        this._email = newEmail;
    }
    @deprecated
    address(): string {
        return `${this.street}\n${this.residence}\n${this.country}`;
    }
}
const p = new Customers ("exampleCustomer", "name@example.com");
p.street = "325 Lafayette Rd";
p.residence = "New Jersey";
```

## Method TypeScript decorators

TypeScript decorators can also be used for **methods**. Exceptions are declaration files, overloading or the “declare” class. In the following example, we are going to use `@enumerable` as a decorator for the `getName` method in the “Person” class:

```typescript
const enumerable = (value: boolean) => {
    return (target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
        propertyDescriptor.enumerable = value;
    }
}
class Person {
    firstName: string = "Julia"
    lastName: string = "Brown"
    @enumerable(true)
    getName () {
        return `${this.firstName} ${this.lastName}`;
    }
}
```

## Property TypeScript decorators

TypeScript decorators for class properties (property decorators) take two parameters, which are the class’s constructor function and the name of the property. In the example below, we use the decorator to display the name of a property (such as the customer name):

```typescript
const printPropertyName = (target: any, propertyName: string) => {
    console.log(propertyName);
};
class Customers {
    @printPropertyName
    name: string = "Julia";
}
```

## Accessor TypeScript decorators

Accessor decorators work on a principle similar to Property decorators, but with one key difference: they include an **additional third parameter**. In this context, that parameter is the Property Descriptor for a customer. When you use an Accessor Decorator to set a value, it updates the Property Descriptor accordingly. In the following code, for example, the boolean value (true or false) of enumerable is modified. Here’s the starting point:

```typescript
const enumerable = (value: boolean) => {
    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
        descriptor.enumerable = value;
    }
}
```

Here’s how to use the decorator:

```typescript
class Customers {
    firstName: string = "Julia";
    lastName: string = "Brown";
    @enumerable(true)
    get name() {
        return `${this.firstName} ${this.lastName}`;
    }
}
```

## Parameter TypeScript decorators

TypeScript Parameter decorators also receive three arguments: the class constructor function, the name of the method, and the index of the parameter. However, the parameter itself cannot be modified, meaning this decorator is **limited to validation purposes**. To access the parameter index, you can use the following code:

```typescript
function print(target: Object, propertyKey: string, parameterIndex: number) {
    console.log(`Decorating param ${parameterIndex} from ${propertyKey}`);
}
```

If you then apply the Decorator parameter, this is the code:

```typescript
class Example {
    testMethod(param0: any, @print param1: any) {}
}
```

Tip Ideal for static websites and apps alike: With [Deploy Now](https://www.ionos.com/hosting/deploy-now "Deploy Now from IONOS") from IONOS, you benefit from simple staging, a quick setup and perfectly coordinated workflows. Find the right plan to suit your needs!


This is a markdown version of: [https://www.ionos.com/digitalguide/websites/web-development/typescript-decorators/](https://www.ionos.com/digitalguide/websites/web-development/typescript-decorators/) for AI/LLM consumption.