iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Decorators

Decorators are functions that wrap classes, methods, fields, or accessors with extra behaviour. TypeScript 5 implements the stage-3 spec — close to what's landing in JavaScript itself.

Method decorator

TS
function log<This, Args extends unknown[], Ret>(
    target: (this: This, ...args: Args) => Ret,
    ctx:    ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Ret>,
) {
    return function (this: This, ...args: Args): Ret {
        console.log(`-> ${String(ctx.name)}(${args.join(', ')})`);
        return target.call(this, ...args);
    };
}

class Calculator {
    @log
    add(a: number, b: number) { return a + b; }
}

new Calculator().add(2, 3);    // logs: -> add(2, 3)

Class decorator

TS
function freeze<T extends new (...args: any[]) => any>(
    target: T,
    _ctx:   ClassDecoratorContext,
) {
    return class extends target {
        constructor(...args: any[]) {
            super(...args);
            Object.freeze(this);
        }
    };
}

@freeze
class Config {
    constructor(public name = 'default') {}
}

Field decorator

TS
function uppercase<This, Value extends string>(
    _target: undefined,
    _ctx:    ClassFieldDecoratorContext<This, Value>,
) {
    return function (this: This, value: Value): Value {
        return value.toUpperCase() as Value;
    };
}

class User {
    @uppercase
    name: string = 'ada';     // becomes 'ADA'
}

Decorator contexts

TS gives each decorator a typed context argument with the kind, name, access, and metadata:

  • ClassDecoratorContext
  • ClassMethodDecoratorContext
  • ClassFieldDecoratorContext
  • ClassGetterDecoratorContext / ClassSetterDecoratorContext / ClassAccessorDecoratorContext

Legacy decorators

Older code (often Angular, NestJS) uses experimental decorators. They look similar but have different signatures and require "experimentalDecorators": true in tsconfig. They live alongside stage-3 — not mutually compatible in the same file.

Tip: Don't use decorators for everyday business logic. They obscure control flow. Reserve them for cross-cutting concerns — logging, validation, dependency injection — and keep the implementations small.

Example

Example
// Stage-3 decorators land in TS 5+
// function log(_: unknown, ctx: ClassMethodDecoratorContext) {
//   return function (this: any, ...args: any[]) {
//     console.log('->', String(ctx.name), args);
//     return (ctx as any).access.get.call(this).call(this, ...args);
//   };
// }
console.log('Decorators wrap classes/methods with extra behaviour');
Try it Yourself »

Exercise

Decorator prefix character.

log

Test yourself

Q1. Modern decorators in TS 5+ are…
Q2. Legacy decorators require the flag…
Q3. Context type for a method decorator is…

Discussion

Loading…