Close

TypeScript - Property Decorators

[Last Updated: Mar 19, 2019]

A Property Decorator is applied on a property declaration.

The property decorator function is called with the following two arguments:

  • Either the constructor function of the class for a static member, or the prototype of the class for an instance member.
  • The name of the property.

As opposed to class and method decorators, a Property Descriptor is not provided as an argument to a property decorator.

Also the return value from the decorator function is ignored.

A property decorator can only be used to observe that a property of a specific name has been declared for a class.

Example

Property Decorator without parameters

Ex1PropertyDecorator.ts

function notNull(target: any, propertyKey: string) {
    Validator.registerNotNull(target, propertyKey);
}

class Validator {
    private static notNullValidatorMap: Map<any, string[]> = new Map();

    //todo add more validator maps

    static registerNotNull(target: any, property: any): void {
        let keys: string[] = this.notNullValidatorMap.get(target);
        if (!keys) {
            keys = [];
            this.notNullValidatorMap.set(target, keys);
        }
        keys.push(property);
    }

    static validate(target: any): boolean {
        let notNullProps: string[] = this.notNullValidatorMap.get(Object.getPrototypeOf(target));
        if (!notNullProps) {
            return true;
        }
        let hasErrors: boolean = false;
        for (const property of notNullProps) {
            let value = target[property];
            if (!value) {
                console.error(property + " value cannot be null");
                hasErrors = true;
            }
        }
        return hasErrors;
    }
}

class Person {
    @notNull
    name: string;

    constructor(name: string) {
        this.name = name;
    }
}

console.log("-- creating instance --");
let person: Person = new Person(null);
console.log(person);
let b = Validator.validate(person);
console.log("validation passed: " + !b);
console.log("-- creating another instance --");
let person2: Person = new Person("Tina");
console.log(person2);
b = Validator.validate(person2);
console.log("validation passed: " + !b);
-- creating instance --
Person { name: null }
name value cannot be null
validation passed: false
-- creating another instance --
Person { name: 'Tina' }
validation passed: true

Property Decorator with parameters

Ex2PropertyDecorator.ts

enum ValidationType {
    NotNull
}

function validate(...types: ValidationType[]) {
    return function (target: any, propertyKey: string) {
        Validator2.registerValidators(target, propertyKey, types);
    }
}

class Validator2 {
    private static notNullValidatorMap: Map<any, string[]> = new Map();
    //todo add more validator maps

    static registerValidators(target: any, property: any, types: ValidationType[]): void {
        for (const type of types) {
           if(type==ValidationType.NotNull){
               let keys: string[] = this.notNullValidatorMap.get(target);
               if (!keys) {
                   keys = [];
                   this.notNullValidatorMap.set(target, keys);
               }
               keys.push(property);
           }
        }//todo add more validators if else
    }

    static validate(target: any): boolean {
        let notNullProps: string[] = this.notNullValidatorMap.get(Object.getPrototypeOf(target));
        if (!notNullProps) {
            return true;
        }
        let hasErrors: boolean = false;
        for (const property of notNullProps) {
            let value = target[property];
            if (!value) {
                console.error(property + " value cannot be null");
                hasErrors = true;
            }
        }
        return hasErrors;
    }
}

class Person2 {
    @validate(ValidationType.NotNull)
    name: string;

    constructor(name: string) {
        this.name = name;
    }
}

console.log("-- creating instance --");
let person3: Person2 = new Person2(null);
console.log(person3);
let b2 = Validator2.validate(person3);
console.log("validation passed: " + !b2);
console.log("-- creating another instance --");
let person4: Person2 = new Person2("Tina");
console.log(person4);
b2 = Validator2.validate(person4);
console.log("validation passed: " + !b2);
-- creating instance --
Person2 { name: null }
name value cannot be null
validation passed: false
-- creating another instance --
Person2 { name: 'Tina' }
validation passed: true

Example Project

Dependencies and Technologies Used:

  • Typescript 3.3.3333
Property Decorators Examples Select All Download
  • typescript-property-decorator-examples
    • Ex1PropertyDecorator.ts

    See Also