如何在TypeScript中向装饰器添加可选参数?

时间:2016-10-25 07:50:52

标签: typescript decorator typescript1.8

我想创建一个可选择接受参数的字段装饰器。 参数应包含以下任何值:nothing,boolean或function。 我知道怎么做,但我对结果并不百分之百:

export class TestClass{

   @Required(isRequired) 
   public testField: string;

}

export function isRequired():boolean{
   ... some validation logic, maybe depending on other fields...
   return result;
}

实施@Required:

export function Required(expression?: boolean|Function): Function {
    return (target: any, key: string) => {
        if (expression === null || typeof expression == 'undefined') {
            expression = true;
        }
        console.log("Required found: " + expression, ":", target, key);
        ... register the field and its validation expression for later usage
    }
}

所以这个工作正常,但是当我不想添加表达式(因此使用默认的" true"表达式)时,我希望能够像这样编写它:

class TestClass{

   @Required
   public testField: string;

}

我收到TypeScript错误(TS1240)说:

  

在调用时无法解析属性修饰符的签名   表达。提供的参数与任何呼叫签名都不匹配   目标

所以我需要写@Required()

class TestClass{

   @Required()
   public testField: string;

}

是否可以编写一个可选择带参数的装饰器实现,当没有指定该参数时,不需要添加"()" ?

2 个答案:

答案 0 :(得分:3)

实际上,有可能。

这是一个有效的示例:

export type Target = {
  new (...args: any[]): any,
  name: string
};

export function Component(target: Target): void;
export function Component(name: string): (target: Target) => void;
export function Component(nameOrTarget: string | Target) {
  if (typeof nameOrTarget !== 'string') {
    console.log(nameOrTarget.name, ' is now decorated');
  } else {
    return function (target: Target) {
      const name = nameOrTarget || target.name;
      console.log(name, ' is now decorated');
    };
  }
}

@Component
export class MyDatabase { }

@Component('Hello Db')
export class MyHelloDatabase { }

最重要的部分是以下两行:

export function Component(target: Target): void;
export function Component(name: string): (target: Target) => void;

如果有人需要更多信息,请查看此GitHub issue

答案 1 :(得分:2)

不,你可能做不到。
原因是装饰器具有特定的签名(根据装饰器的类型而变化) 如果您使用装饰器功能,那么您不需要括号,但如果您使用a decorator factory(就像您在示例中所做的那样),那么您必须使用括号来调用它。

你可以做的是将两者分成两个不同的功能:

function Required(target: any, key: string, expression?: boolean | Function) {
    if (expression === null || typeof expression == 'undefined') {
        expression = true;
    }
    console.log("Required found: " + expression, ":", target, key);
}

function RequiredWith(expression: boolean | Function): Function {
    return (target: any, key: string) => {
        return Required(target, key, expression);
    }
}

然后你可以:

class TestClass {
    @Required
    public testField: string;
}

或者:

class TestClass2 {
    @RequiredWith(true)
    public testField: string;
}

code in playground