In Angular, decorators are a core part of how the framework works. Whether you're building components, services, directives, or pipes—you're using decorators all the time. But what are they exactly, and how do they work?
What Is a Decorator?
Common Angular Decorators
@Component
This marks a class as an Angular component and tells Angular how to use it in the DOM.
tsimport { Component } from '@angular/core';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
})
export class UserComponent {
name = 'John';
}
What it does: Angular knows this class is a component, and it should be rendered wherever <app-user>
is used in HTML.
@NgModule
This defines a module, which is a group of related components, directives, pipes, and services.
tsimport { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
bootstrap: [AppComponent],
})
export class AppModule {}
@Injectable
Used to mark a class as available for dependency injection (DI).
tsimport { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class AuthService {
login() {
// logic here
}
}
Note: providedIn: 'root'
makes the service available application-wide and tree-shakable.
@Input and @Output
Used in components to allow data to be passed between parent and child components.
tsimport { Input, Output, EventEmitter, Component } from '@angular/core';
@Component({
selector: 'app-user-card',
template: '<div>{{ name }}</div>',
})
export class UserCardComponent {
@Input() name: string = '';
@Output() selected = new EventEmitter<string>();
selectUser() {
this.selected.emit(this.name);
}
}
@HostListener and @HostBinding
These decorators are used in directives or components to listen to events and bind to host element properties.
tsimport { Directive, HostListener, HostBinding } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
@HostBinding('style.backgroundColor') bg = '';
@HostListener('mouseenter') onMouseEnter() {
this.bg = 'yellow';
}
@HostListener('mouseleave') onMouseLeave() {
this.bg = '';
}
}
This directive highlights the element when hovered.
Custom Decorators in Angular
Angular gives you powerful built-in decorators, but you can also create your own. Custom decorators are useful for logging, validation, caching, role-based control, and more. They are just TypeScript functions with a special signature.
Example 1: Method Logging Decorator
tsexport function LogMethod() {
return function (target: any, key: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(\`[Log] \${key} called with:\`, args);
return original.apply(this, args);
};
return descriptor;
};
}
Usage:
tsexport class UserService {
@LogMethod()
getUser(id: number) {
return { id, name: 'Test User' };
}
}
Every time getUser
is called, a log message is printed with the method name and arguments.
Example 2: Required Property Decorator
This custom property decorator throws an error if a required property is set to null
or undefined
.
tsexport function Required(target: any, propertyKey: string) {
let value: any;
const getter = () => value;
const setter = (newVal: any) => {
if (newVal === null || newVal === undefined) {
throw new Error(\`Property "\${propertyKey}" is required.\`);
}
value = newVal;
};
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true,
});
}
Usage:
tsexport class Product {
@Required
name: string;
constructor(name: string) {
this.name = name;
}
}
If someone creates a Product
with null
or undefined
as the name, an error will be thrown immediately.
Key Takeaways
- Decorators are a core part of Angular’s architecture. They add metadata that tells Angular how to treat your classes and properties.
- They are powered by TypeScript’s experimental decorator feature.
- You can create custom decorators to reuse logic like logging or validation.
- Use decorators to keep your code cleaner, more declarative, and easier to maintain.