← Back to TypeScript Course | Chapter 10: Decorators | Lesson 4 of 7

Property Decorators

Modern TypeScript uses field decorators to customize class fields. A field decorator receives the initial field value when instances are created and can return an initializer that transforms that value.
Syntax
typescript
function DecoratorName(target: any, key: string) {
  // inspect the property
}

class ClassName {
  @DecoratorName
  property: type;
}

Basic Field Decorator

A field decorator runs once when the class field is defined and can read or transform the field's initial value before any instance is created, giving you a hook into how that property starts out.

Example: Basic Field Decorator

typescript
function logged(value: undefined, context: ClassFieldDecoratorContext) {
  console.log(`Field ${String(context.name)} is being defined`);
}
class User {
  @logged
  name = "Ravi";
}
new User();

Transforming Initial Values

Because the decorator sees the field's initializer function, it can wrap it to normalize or validate the starting value, such as trimming a string or clamping a number, before the property is ever assigned.

Example: Transforming Initial Values

typescript
function trimmed(value: undefined, context: ClassFieldDecoratorContext) {
  return function (this: any, initial: string) {
    return initial.trim();
  };
}
class Form {
  @trimmed
  username = "  Ravi  ";
}
console.log(new Form().username);

Field Decorator Initializers

The decorator receives the class's field initializer as an argument, so returning a new initializer function lets you completely swap out how the field's default value is computed.

Example: Field Decorator Initializers

typescript
function withDefault(defaultValue: number) {
  return function (value: undefined, context: ClassFieldDecoratorContext) {
    return function (this: any, initial: number) {
      return initial ?? defaultValue;
    };
  };
}
class Settings {
  @withDefault(10)
  volume = 10;
}
console.log(new Settings().volume);

Field Decorator Factories

A field decorator factory accepts arguments at the point of use, so the same decorator can enforce a different rule per field, like a minimum length for one string field and a different one for another.

Example: Field Decorator Factories

typescript
function minLength(min: number) {
  return function (value: undefined, context: ClassFieldDecoratorContext) {
    return function (this: any, initial: string) {
      if (initial.length < min) throw new Error(`Too short, need ${min}`);
      return initial;
    };
  };
}
class Account {
  @minLength(3)
  username = "Ravi";
}
console.log(new Account().username);

Static and Instance Fields

TypeScript's decorator metadata distinguishes between static fields (attached to the class itself) and instance fields (attached to each object), and a decorator needs to check which kind it's decorating before assuming shared state.

Example: Static and Instance Fields

typescript
function describe(value: undefined, context: ClassFieldDecoratorContext) {
  console.log(`${String(context.name)} is ${context.static ? "static" : "instance"}`);
}
class Counter {
  @describe
  static total = 0;
  @describe
  count = 0;
}
new Counter();
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Expecting a field decorator to receive the field value directly, when standard decorators get undefined and must return an initializer function.
  2. Forgetting that the initializer runs for each instance, so shared mutable state inside it is misleading.
  3. Using a field decorator on a method or vice versa, since each decorator type takes a different context.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.