How to describe validators for two possible types: array or string?
Two decorators seems not working.
@IsBoolean()
@IsString()
private readonly foo: boolean | string;
There is currently no way of doing this. What is your use-case? Why do you accept both string and boolean? Do you convert it to one of them after validating with class-validator?
Yes. It's this property
https://github.com/javascript-obfuscator/javascript-obfuscator/pull/180/files#diff-15b001f4b5c1e28b83dca39130e3531bR121
Identifiers prefix can be as string and then it will using as is, or as boolean and then it will disabled (false value) or random generated (true value)
I removed boolean type so it's not important for me now, but anyway nice feature to have.
How about a signature like:
@IsType(Array<(val: any) => boolean>)
@IsType([
val => typeof val == 'string',
val => typeof val == 'boolean',
])
private readonly foo: boolean | string;
It would be nice!
@NoNameProvided Personally i'm against complex logic in decorator definitions.
Imagine having repeat those val => typeof val == 'string' in every property you want to validate. It quickly gets messy. Especially when you will need to change the logic of validating - then you will need to look for all references and change them one by one.
I suggest you to implement similar solution to the one i posted here.
Or if it's common to validate multi-typed properties in your project, you can use custom decorator factory to specify which type you want to validate.
import { registerDecorator, ValidationArguments, ValidationOptions, Validator } from "class-validator";
const typeValidator = {
"string": function (value: any, args: ValidationArguments) {
const validator = new Validator();
return validator.isString(value);
},
"int": function (value: any, args: ValidationArguments) {
const validator = new Validator();
return validator.isInt(value);
}
// Add more here
};
export function IsType(types: (keyof (typeof typeValidator))[], validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
registerDecorator({
name: "wrongType",
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
return types.some(v => typeValidator[v](value, args));
},
defaultMessage(validationArguments?: ValidationArguments) {
const lastType = types.pop();
if (types.length == 0)
return `Has to be ${lastType}`;
return `Can only be ${types.join(", ")} or ${lastType}.`;
}
}
});
};
}
And then usage is very simple and clean:
class example {
@IsType(["string", "int"])
public someValue: number | string;
}
@ZBAGI How would you replicate IsType for nested objects? @IsType([TypeA, TypeB])?
It should work exactly like example shows. If you meant an array then ValidationOptions.each set to true should do the work.
class example {
@IsType(["string", "int"], { each: true })
public someValue: (number | string)[];
}
@ZBAGI Thanks! I meant to ask if it could work with custom defined types? If I defined ClassA and ClassB, would this method work?
You can add whatever type checking function you wish
Here is example that will look for string in property typeName
const typeValidator = {
"typeOne": function (value: any, args: ValidationArguments) {
if(typeof value === "object")
return false; // if its not an object it cannot be 'typeOne' object
return value['typeName'] == "typeOne"; // Check typeName property and if it is typeOne then it is typeOne 'type'.
},
};
And here is the usage:
class example {
@IsType(["typeOne"])
public someValue: object;
}
So many duplicated topics about it and we still have to implement our version ?
You could try this:
@IsArray()
@IsString({each: true})
Most helpful comment
How about a signature like: