如何解决如何使一组装饰器在Typescript中易于重用 小型装饰工厂工厂
TL; DR
如何将装饰器(从库中)分组到1个可重复使用的装饰器中
问题
每次我的REST API收到请求时,它将验证提供的主体属性(使用class-validator
库)。每条路线都有自己专用的验证类(在代码中称为Dtos)(请参见示例)
每个提供的body属性都有一些验证规则,有时这些验证规则可能会变得非常复杂,其他工程师应该能够轻松地重用这些验证规则。
示例
路线1:创建公司
POST - /api/company
>> Parameters: name,domain,size,contact
class CreateCompanyDto implements Dto {
@IsString({message: 'Must be text format'})
@MinLength(2,{ message: "Must have at least 2 characters" })
@MaxLength(20,{ message: "Can't be longer than 20 characters" })
@IsDefined({ message: 'Must specify a receiver' })
public name!: string;
@MaxLength(253,{ message: "Can't be longer than 253 characters" })
@IsFQDN({},{message: 'Must be a valid domain name'})
@IsDefined({ message: 'Must specify a domain' })
public domain!: string;
@MaxLength(30,{ message: "Can't be longer than 30 characters" })
@IsString({message: 'Must be text format'})
@IsDefined({ message: 'Must specify a company size' })
public size!: string;
@IsPhoneNumber(null,{message: 'Must be a valid phone number'})
@IsDefined({ message: 'Must specify a phone number' })
public contact!: string;
}
路线2:公司更新
PUT - /api/company
>> Parameters: id,name,contact
class UpdateCompanyDto implements Dto {
@IsUUID()
@IsDefined({ message: 'Must be defined' })
public id!: string;
@IsString({ message: 'Must be text format' })
@MinLength(2,{ message: "Can't be longer than 20 characters" })
@IsOptional()
public name!: string;
@MaxLength(253,{ message: 'Must be a valid domain name' })
@IsOptional()
public domain!: string;
@MaxLength(30,{ message: "Can't be longer than 30 characters" })
@IsString({ message: 'Must be text format' })
@IsOptional()
public size!: string;
@IsPhoneNumber(null,{ message: 'Must be a valid phone number' })
@IsOptional()
public contact!: string;
}
我要搜索的内容
就像您在示例中看到的那样,一个验证类需要使用另一个验证类的属性并不少见。
问题是,如果工程师向随机验证类中的属性添加1条验证规则,则其他验证类将不会动态更新。
问题:确保装饰器更改/添加后,其他验证类了解更新的最佳方法是什么。
是否有某种方法可以将它们组合在一起成为变量/装饰器?任何打字稿专家的任何帮助都将受到赞赏!
可接受的结果:
class CreateCompanyDto implements Dto {
@IsCompanyName({required: true})
public name!: string;
@IsCompanyDomain({required: true})
public domain!: string;
@isCompanySize({required: true})
public size!: string;
@isCompanyContact({required: true})
public contact!: string;
}
class UpdateCompanyDto implements Dto {
@IsCompanyId({required: true})
public id!: string;
@IsCompanyName({required: false})
public name!: string;
@IsCompanyDomain({required: false})
public domain!: string;
@isCompanySize({required: false})
public size!: string;
@isCompanyContact({required: false})
public contact!: string;
}
解决方法
由于装饰器的功能性质,您可以轻松定义自己的装饰器工厂以仅调用所有必需的验证器:
export function IsCompanyName({ required }: { required: boolean }): PropertyDecorator {
return function (target: any,propertyKey: string | symbol): void {
IsString({ message: 'Must be text format' })(target,propertyKey);
MinLength(2,{ message: "Must have at least 2 characters" })(target,propertyKey);
MaxLength(20,{ message: "Can't be longer than 20 characters" })(target,propertyKey);
if (required)
IsDefined({ message: 'Must specify a receiver' })(target,propertyKey);
else
IsOptional()(target,propertyKey);
}
}
小型装饰工厂工厂
export function ValidatorComposer(validators: PropertyDecorator[],name: string): (options: { required: boolean }) => PropertyDecorator {
return function ({ required }: { required: boolean }) {
return function (target: any,propertyKey: string | symbol): void {
validators.forEach((validator) => validator(target,propertyKey));
if (required)
IsDefined({ message: 'Must specify a ' + name })(target,propertyKey);
else
IsOptional()(target,propertyKey);
}
}
}
,
您可以通过定义自己的装饰器来链接装饰器。请注意,我之前没有使用过class-validator
库,因此您需要测试一下。但这是这样的:
在这里,我定义了一个装饰器IsCompanyName
,并在示例中将其称为验证装饰器。我定义了ValidationOptions
接口来传递给装饰器。是否需要此opts
参数由您决定。如果未指定选项,则由您决定默认行为。在我的示例中,我将其设置为可选,并使其表现为默认情况下是必需的。仅当定义了IsOptional
并且opts
时,我才调用required === false
装饰器。否则我不称呼它。
interface ValidationOptions {
required?: boolean
}
function IsCompanyName(opts?: ValidationOptions) {
return function (target: any,propertyKey: string) {
IsString({ message: 'Must be text format' })(target,propertyKey);
MinLength(2,propertyKey);
MaxLength(20,propertyKey);
IsDefined({ message: 'Must specify a receiver' })(target,propertyKey);
if (opts && opts.required === false) {
IsOptional()(target,propertyKey);
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。