Property Decorators
In this page:
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
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
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
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
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
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();
- Expecting a field decorator to receive the field value directly, when standard decorators get
undefinedand must return an initializer function. - Forgetting that the initializer runs for each instance, so shared mutable state inside it is misleading.
- 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: