Skip to content
C.W.K.
Stream
Lesson 06 of 06 · published

TC39 Decorators: The Stage 3 Model

~11 min · classes, decorators, tc39, stage-3

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"A decorator is a function that participates when a class element is defined or initialized, wrapping behavior without hiding the underlying contract."

A value and a context object

In the current decorators model, a decorator receives the value being decorated and a context object. A method decorator receives the original method plus a ClassMethodDecoratorContext containing the element's name, kind, static and private status, and access helpers.

The decorator may return a replacement value or return nothing. A replacement method can add logging or timing while preserving the original call. Returning undefined leaves the original method in place. These hooks are installed according to class definition and initialization semantics, not improvised at each call site.

What can be decorated

The TC39 Stage 3 model covers classes, methods, getters, setters, fields, and auto-accessors. Accessors are supported: getters and setters are decorated as individual elements, while an accessor declaration uses the auto-accessor decorator shape.

Parameter decorators are not part of this model. You may still encounter them in TypeScript's legacy experimentalDecorators ecosystem, but that is a different contract from the decorator behavior TypeScript 5.0 supports without the flag.

Do not mix the legacy and current contracts

experimentalDecorators implements the calling convention of an older proposal. The current model passes a value and context object and is not compatible with emitDecoratorMetadata or parameter decorators. Check which model a library requires before choosing compiler settings or reusing a decorator function.

New code should prefer the current model, but a framework that depends on legacy metadata needs a deliberate migration. The arguments, return values, and supported capabilities differ enough that an existing decorator is not automatically portable.

The initializer hook is addInitializer

A context object's addInitializer method registers work for the appropriate class or instance initialization point. It can, for example, bind a decorated method to each instance. Use the actual context type for the decorated element instead of relying on obsolete hook names.

Decorators are a focused tool for genuine cross-cutting behavior. Use them when one rule truly spans multiple class elements, not when an ordinary function or explicit composition would keep the control flow clearer.

Code

Stage 3 decorators — methods and classes·typescript
// A simple method decorator (Stage 3 syntax).
function logged(originalMethod: any, context: ClassMethodDecoratorContext) {
  const methodName = String(context.name);
  return function (this: any, ...args: any[]) {
    console.log(`Calling ${methodName}(${args.join(', ')})`);
    const result = originalMethod.call(this, ...args);
    console.log(`${methodName} returned ${result}`);
    return result;
  };
}

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

const c = new Calculator();
c.add(2, 3);
// Output:
//   Calling add(2, 3)
//   add returned 5

// Class decorator — seals the class and returns the same value.
function sealed<T extends new (...args: any[]) => any>(
  Ctor: T,
  context: ClassDecoratorContext,
) {
  Object.seal(Ctor);
  Object.seal(Ctor.prototype);
  return Ctor;
}

@sealed
class Greeter {
  greet() { return 'hi' }
}

External links

Exercise

Write a @timed method decorator and apply it to a computation method. Confirm that it preserves the original return value and this binding while reporting the elapsed time.
Hint
Return a replacement function that reads performance.now() before and after originalMethod.call(this, ...args), then returns the original result unchanged.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.