How to create a TypeScript @Relationship decorator for a property

457 views Asked by At

Consider the following code:

export class Model {
    constructor(input: any) {
        this.deserialize(input);
    }

    deserialize(input: any): Model {
        Object.assign(this, input);
        return this;
    }
}

export class Body extends Model {
    Success: boolean;
    @Relationship Result: Result;
    //...
}

export class Result extends Model {
    Skip: number;
    Top: number;
    TotalCount: number;
    //...
}

The script receives a json and starts a new instance of the Body class:

//...
let body = new Body({
    Sucess: true,
    Result: {
        Skip: 0,
        Top: 0,
        TotalCount: 20
        //...
    }
    //...
});

The deserialize method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

For the Result property to start correctly, a change is required in the deserialize method:

deserialize(input: any): Model {
    Object.assign(this, input);
    this.Result = new Result(input.Result);
    return this;
}

The problem that the Model class is generic and can not implement the solution described.

I do not want to declare the deserialize method on each child class.

As the problem can be solved using the decorator "@Relationship"?

1

There are 1 answers

0
Pavel On

Yes, it is possible. There detailed example, that does something similar, and there detailed description(russian), how it works

In short, you should do next:

  1. Enable emitDecoratorsMetadata in tsconfig and install reflect-metadata polyfill.
  2. In decorator mark field, by applying metadata via call Reflect.defineMetadata("SomeUniqueDecoratorKey", true, target, fieldName)
  3. In deserialize function iterate through fields, and check if SomeUniqueDecoratorKey metadata is true for this field. If it is true, then get field type constructor and create new instance.

     var fieldTypeCtor = Reflect.getMetadata("design:type", target, fieldName);
     var newInstance = new fieldTypeCtor(yourData);