Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a parameter decorator in TypeScript?

I've been trying to use a parameter decorator @logParameter:

class Person {

  public name: string;
  public surname: string;

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

  public saySomethingAsync(something: string, @logParameter cb: (said : string) => void) { 
    cb(this.name + " " + this.surname + " says: " + something); 
  }
}

My problem is that when I try to implement the decorator. All the changes that I do to the target are ignored.

I've been reading some documentation and the parameter decorators are not able to modify the target.

A parameter decorator function is a function that accepts three arguments: The function that contains the decorated parameter, the property key of the member (or undefined for a parameter of the constructor), and the ordinal index of the parameter. The return value of this decorator is ignored.

The documentation says that I can annotate use the parameter decorator to

annotate the target and index

and then use a method decorator to read the annotation. It would be something like something like:

  @readParameterAnnotations
  public saySomethingAsync(something: string, @logParameter cb: (said : string) => void) { 
    cb(this.name + " " + this.surname + " says: " + something); 
  }

My problem is that I don't understand how can I add an annotation to the target if all changes to the target are ignored?

function logParameter(target: any, key: string, index: number) {
  // how can I annotate the target?
}

Is using reflect-metadata the only way?

function logParameter(target: any, key: string, index: number) {
  Reflect.defineMetadata("log_parameters", index, target, key);
}
like image 741
Remo H. Jansen Avatar asked Jun 05 '15 14:06

Remo H. Jansen


1 Answers

The return value of this decorator is ignored.

This is irrelevant to your situation. The return value of parameter decorators is ignored because they don't need to be able to replace anything (unlike method and class decorators which can replace the descriptor).

My problem is that when I try to implement the decorator. All the changes that I do to the target are ignored.

The target is the object's prototype. It works fine:

class MyClass {
    myMethod(@logParam myParameter: string) {}
}

function logParam(target: any, methodKey: string, parameterIndex: number) {
    target.test = methodKey;
    // and parameterIndex says which parameter
}

console.log(MyClass.prototype["test"]); // myMethod
var c = new MyClass();
console.log(c["test"]); // myMethod

Just change that situation to put the data where you want it (using Reflect.defineMetadata is probably best).

like image 68
David Sherret Avatar answered Nov 13 '22 00:11

David Sherret