如何向 TypeScript 中的装饰器添加可选参数?
How to add an optional parameter to a decorator in TypeScript?
我想创建一个字段装饰器,它可以选择性地接受一个参数。
该参数应包含以下任何值:无、布尔值或函数。
我知道该怎么做,但我对结果不是 100% 满意:
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) 说:
Unable to resolve signature of property decorator when called as an
expression. Supplied parameters do not match any signature of call
target
所以我需要写@Required()
class TestClass{
@Required()
public testField: string;
}
是否可以编写一个带有可选参数的装饰器实现,并且当未指定该参数时无需添加“()”?
不,你可能做不到。
原因是装饰器具有特定的签名(根据装饰器的类型而有所不同)。
如果您使用装饰器函数,则不需要括号,但如果您使用 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;
}
其实是可以的
这是一个工作示例:
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。
我想创建一个字段装饰器,它可以选择性地接受一个参数。 该参数应包含以下任何值:无、布尔值或函数。 我知道该怎么做,但我对结果不是 100% 满意:
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) 说:
Unable to resolve signature of property decorator when called as an expression. Supplied parameters do not match any signature of call target
所以我需要写@Required()
class TestClass{
@Required()
public testField: string;
}
是否可以编写一个带有可选参数的装饰器实现,并且当未指定该参数时无需添加“()”?
不,你可能做不到。
原因是装饰器具有特定的签名(根据装饰器的类型而有所不同)。
如果您使用装饰器函数,则不需要括号,但如果您使用 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;
}
其实是可以的
这是一个工作示例:
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。