Class 验证器:使用 class 成员作为装饰器参数
Class validator: Use class member as decorator argument
我有一个注册 DTO,其中一个成员依赖于另一个成员。
zip
上的 IsPostalCode
需要知道 countryCode/locale,这是其他 class 成员之一。
是否可以使用 class 成员作为修饰参数?
import {
IsEmail,
IsISO31661Alpha2,
IsPostalCode,
IsString
} from "class-validator"
export class SignupDto {
@IsEmail()
email: string
@IsString()
password: string
@IsISO31661Alpha2()
countryCode: string
// Something like this
@IsPostalCode(this.countryCode)
zip: string
}
由于装饰器在打字稿中的工作方式,装饰器无法固有地使用其中的 class 属性。您可以创建一个 custom validation decorator 来读取 class 的其他属性并正确验证 zip 属性,但这可能需要一些工作才能开始。
所以回答你的问题:
Is it possible to use a class member as decorator argument?
不,不是。
您可以像下面这样创建自定义验证器:
import {
ValidationOptions,
registerDecorator,
ValidationArguments,
buildMessage,
} from 'class-validator';
/**
* Install validator package from npm. class-validator uses validator under the
* hood
*/
import {isISO31661Alpha2,isPostalCode} from 'validator';
export function IsPostalCodeOf(
property: string,
validationOptions?: ValidationOptions,
) {
// eslint-disable-next-line @typescript-eslint/ban-types
return function(object: Object, propertyName: string) {
registerDecorator({
name: 'isPostalCodeOf',
target: object.constructor,
propertyName: propertyName,
constraints: [property],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
// Getting the country code field from the argument.
// countryCode field from SignupDto
const [countryCodeField] = args.constraints;
// Getting the value of the countryCode Field
const countryCode = (args.object as any)[countryCodeField];
// Checking if the country code is valid even though it is checked
// at class level
if (!isISO31661Alpha2(countryCode)) {
// Invalid county code
return false;
}
// Checks if the value (zip) belongs in the extracted countryCode
// field
return isPostalCode(value,countryCode);
},
// Specifiy your error message here.
defaultMessage: buildMessage(
eachPrefix =>
`${eachPrefix} $property must be a valid postal
code in the specified country `,
validationOptions,
),
},
});
};
}
用法:
export class SignupDto {
@IsEmail()
email: string
@IsString()
password: string
@IsISO31661Alpha2()
countryCode: string
@IsPostalCodeOf('countryCode')
zip: string
}
您可以使用 Validate
装饰器并创建自定义验证方法。例如,假设您的 dto 上有属性 zip
和 countryCode
:
@ValidatorConstraint({ name: 'isPostalCodeByCountryCode', async: false })
class IsPostalCodeByCountryCode implements ValidatorConstraintInterface {
validate(zip: string, args: ValidationArguments) {
// @ts-ignore
return isPostalCode(zip, args.object.countryCode);
}
defaultMessage(args: ValidationArguments) {
// @ts-ignore
return `Invalid zip "${args.object.zip}" for country "${args.object.countryCode}"`;
}
}
用法:
@Validate(IsPostalCodeByCountryCode)
public zip: string;
我有一个注册 DTO,其中一个成员依赖于另一个成员。
zip
上的 IsPostalCode
需要知道 countryCode/locale,这是其他 class 成员之一。
是否可以使用 class 成员作为修饰参数?
import {
IsEmail,
IsISO31661Alpha2,
IsPostalCode,
IsString
} from "class-validator"
export class SignupDto {
@IsEmail()
email: string
@IsString()
password: string
@IsISO31661Alpha2()
countryCode: string
// Something like this
@IsPostalCode(this.countryCode)
zip: string
}
由于装饰器在打字稿中的工作方式,装饰器无法固有地使用其中的 class 属性。您可以创建一个 custom validation decorator 来读取 class 的其他属性并正确验证 zip 属性,但这可能需要一些工作才能开始。
所以回答你的问题:
Is it possible to use a class member as decorator argument?
不,不是。
您可以像下面这样创建自定义验证器:
import {
ValidationOptions,
registerDecorator,
ValidationArguments,
buildMessage,
} from 'class-validator';
/**
* Install validator package from npm. class-validator uses validator under the
* hood
*/
import {isISO31661Alpha2,isPostalCode} from 'validator';
export function IsPostalCodeOf(
property: string,
validationOptions?: ValidationOptions,
) {
// eslint-disable-next-line @typescript-eslint/ban-types
return function(object: Object, propertyName: string) {
registerDecorator({
name: 'isPostalCodeOf',
target: object.constructor,
propertyName: propertyName,
constraints: [property],
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
// Getting the country code field from the argument.
// countryCode field from SignupDto
const [countryCodeField] = args.constraints;
// Getting the value of the countryCode Field
const countryCode = (args.object as any)[countryCodeField];
// Checking if the country code is valid even though it is checked
// at class level
if (!isISO31661Alpha2(countryCode)) {
// Invalid county code
return false;
}
// Checks if the value (zip) belongs in the extracted countryCode
// field
return isPostalCode(value,countryCode);
},
// Specifiy your error message here.
defaultMessage: buildMessage(
eachPrefix =>
`${eachPrefix} $property must be a valid postal
code in the specified country `,
validationOptions,
),
},
});
};
}
用法:
export class SignupDto {
@IsEmail()
email: string
@IsString()
password: string
@IsISO31661Alpha2()
countryCode: string
@IsPostalCodeOf('countryCode')
zip: string
}
您可以使用 Validate
装饰器并创建自定义验证方法。例如,假设您的 dto 上有属性 zip
和 countryCode
:
@ValidatorConstraint({ name: 'isPostalCodeByCountryCode', async: false })
class IsPostalCodeByCountryCode implements ValidatorConstraintInterface {
validate(zip: string, args: ValidationArguments) {
// @ts-ignore
return isPostalCode(zip, args.object.countryCode);
}
defaultMessage(args: ValidationArguments) {
// @ts-ignore
return `Invalid zip "${args.object.zip}" for country "${args.object.countryCode}"`;
}
}
用法:
@Validate(IsPostalCodeByCountryCode)
public zip: string;