Decorators: what they are, ahead of NestJS
Decorators are special annotations — @Something — you attach to classes, methods, or properties to add
behaviour or metadata. You will meet them constantly in Angular and NestJS (and this is the main
reason the Full-Stack course, which uses NestJS, needs you to understand them). This lesson demystifies
what a decorator is, so that when you see @Injectable() or @Get() in framework code, it is not
magic — it is a function.
What a decorator is
A decorator is, at heart, a function that receives what it decorates and can modify it or attach
information to it. The @ syntax is sugar for calling that function on the thing below it:
@Component({ selector: "app-root" }) // this is a decorator applied to the class
class AppComponent { }
@Component({...}) calls a Component function, passing it the AppComponent class (and here, some
configuration { selector: "app-root" }). The function can then register the class, attach metadata to
it, or wrap it — whatever the framework needs. The decorator runs when the class is defined, once. So a
decorator is not new syntax to fear; it is a function call in disguise, positioned above the thing it acts
on.
Why frameworks love them
Decorators let a framework add a lot of behaviour with a tiny, readable annotation. Compare what
@Injectable() in NestJS means — "register this class so the framework can create and inject it" —
against the amount of wiring you would write by hand. The decorator hides that wiring behind one line:
// NestJS — decorators everywhere, each hiding real machinery
@Injectable()
class UserService {
findAll(): User[] { return []; }
}
@Controller("users")
class UserController {
constructor(private userService: UserService) {} // injected — the framework provides it
@Get()
findAll() {
return this.userService.findAll();
}
@Get(":id")
findOne(@Param("id") id: string) {
return `user ${id}`;
}
}
Read it: @Controller("users") registers a controller for the /users route, @Get() maps a method to
a GET request, @Param("id") extracts a route parameter. Each is a function the framework provides, and
together they declare an entire HTTP API declaratively. This is the shape of a NestJS backend — the
Full-Stack course is built on exactly this, and now you can see decorators for what they are: functions
that wire your classes into the framework.
The kinds of decorator
Decorators can be applied to several things, and each kind of decorator receives different arguments:
@ClassDecorator // on a class — receives the class
class Example {
@PropertyDecorator // on a property
name!: string;
@MethodDecorator // on a method
doThing() {}
method(@ParameterDecorator id: string) {} // on a parameter
}
- Class decorators receive the class — used to register, wrap, or add metadata to it (
@Injectable,@Component). - Method decorators receive the method — used to wrap it (logging, caching, access control, route
mapping like
@Get). - Property and parameter decorators attach metadata to a property or parameter (
@Input,@Param).
You will mostly use framework decorators, not write your own — but knowing the kinds explains why
@Get() (method), @Controller() (class), and @Param() (parameter) appear in different positions.
Writing a simple one, to demystify
To prove there is no magic, here is a method decorator that logs calls — this is the whole idea:
function logged(originalMethod: any, context: any) {
return function (this: any, ...args: any[]) {
console.log(`Calling ${String(context.name)} with`, args);
return originalMethod.call(this, ...args);
};
}
class Calculator {
@logged
add(a: number, b: number): number {
return a + b;
}
}
new Calculator().add(2, 3); // logs "Calling add with [2, 3]", then returns 5
logged receives the original add method and returns a new function that logs, then calls the
original. Applying @logged above add replaces add with the wrapped version. That is all a decorator
does — receive something, return a modified version (or record metadata). The framework decorators do far
more sophisticated things, but the mechanism is exactly this.
The important caveats
Two things you must know before relying on decorators:
There are two versions, and they differ. Decorators were a long-standing experimental TypeScript
feature (enabled by "experimentalDecorators": true in tsconfig), and Angular and current NestJS use
that version, often alongside "emitDecoratorMetadata": true (which emits type information decorators
can read, powering dependency injection). Meanwhile, a standardised decorators proposal reached
JavaScript and modern TypeScript (5.0+) supports it without the experimental flag — but its shape is
different, and the frameworks have not all moved to it. So which decorators you write depends on your
framework's setup. For NestJS/Angular today, you enable experimentalDecorators and
emitDecoratorMetadata; the framework's docs tell you the exact config. This is a real source of
confusion, and the honest answer is "follow your framework's required tsconfig".
Decorators are one of the few TypeScript features with runtime effect. Unlike types (erased), decorators run — they are real code that executes when classes are defined, so they add to your bundle and have runtime behaviour. This is why they can do dependency injection and routing that types cannot.
The realistic takeaway
For this foundation course, the goal is recognition, not authorship. You will rarely write a custom
decorator; you will constantly use framework ones. So the thing to carry forward is: a decorator is a
function applied with @ that wires your class into a framework — @Injectable(), @Controller(),
@Get() are functions that register and configure your code. When you reach the Full-Stack course and
see a NestJS controller full of decorators, you will read it as "these annotations connect this class to
the HTTP framework", not as inexplicable magic. That understanding is the whole point of this lesson —
and it is exactly the bridge from TypeScript-the-language to the Android-of-the-backend that NestJS is.
Check your work
What a decorator is. A function applied with @ that receives what it decorates (a class, method,
property, or parameter) and can modify it or attach metadata.
When a decorator runs. When the thing it decorates is defined — once, at definition time.
Why frameworks use them. To add a lot of behaviour (registration, injection, routing) with one readable annotation, hiding the wiring.
The kinds. Class, method, property, and parameter decorators — each receiving different arguments,
which is why @Controller (class), @Get (method), and @Param (parameter) sit in different positions.
What a method decorator like logged does. Receives the original method and returns a wrapped
version — the whole mechanism.
The two-versions caveat. An older experimentalDecorators version (used by Angular/NestJS, often with
emitDecoratorMetadata) and a newer standardised version (TS 5+, no flag) that differ — follow your
framework's required tsconfig.
Decorators and runtime. Unlike types, decorators run — real code with runtime effect and bundle cost, which is how they do injection and routing.
The takeaway for this course. Recognition, not authorship — a decorator wires your class into a framework; you will read NestJS/Angular decorators, rarely write your own.
Practice
- Explain, in one sentence, what
@Component({ selector: "app-root" })does to the class below it. - Read the NestJS controller example and describe what each decorator (
@Controller,@Get,@Param) contributes. - Write the standard-form
loggedmethod decorator (the(originalMethod, context)shape shown above, which runs on modern TypeScript with no flag). Confirm it logs and still returns the right value. Then note that the experimental form Angular/NestJS use has a different signature and needsexperimentalDecorators. - Identify which of
@Injectable,@Get,@Input,@Paramare class, method, property, or parameter decorators. - Explain why decorators, unlike types, have a runtime cost.
- Describe the two decorator versions and why your tsconfig depends on your framework.
- Find a decorator in framework code (or the example here) and describe it as "a function that ..." to prove it is not magic.
Official documentation
- TypeScript — Decorators — The (experimental) decorators used by Angular/NestJS.
- TypeScript 5.0 — Decorators — The standardised version.
- NestJS — Controllers — Decorators in a real backend framework.
- Angular — Decorators — Where you will use them most on the front end.
Next module — Writing TypeScript Worth Reading: the difference between code that compiles and code worth hiring.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship