class-validator
class-validator copied to clipboard
feat: support multi-dimensional arrays
Hello, I am trying to validate the arrays in arrays but I could not find a correct method.
The structure looks like this:
class MyInnerDto {
@IsString()
name: string;
}
class TestDto {
@IsArray({ each: true })
myArray:MyInnerDto[][];
}
Hello,
I've the same kind of issue with Map and Array values.
The test case below show validation error on nestedMap
but not on nestedWithArray
.
Is there another tips to validate this kind of structure ? or it's a bug ?
With class-validator": "0.11.0"
import { IsString, ValidateNested, Validator } from 'class-validator';
describe('NestedValidation', () => {
class NestedClass {
@IsString()
name: string;
constructor(name: any) {
this.name = name;
}
}
class MasterClass {
@ValidateNested({ each: true })
nestedMap: Map<string, NestedClass>;
@ValidateNested({ each: true })
nestedWithArray: Map<string, NestedClass[]>;
constructor(
nestedMap: Map<string, NestedClass>,
nestedWithArray: Map<string, NestedClass[]>,
) {
this.nestedMap = nestedMap;
this.nestedWithArray = nestedWithArray;
}
}
describe('validation', () => {
let validator: Validator;
beforeAll(() => {
validator = new Validator();
});
it('should validate nested object array', async () => {
const nestedMap = new Map<string, NestedClass>();
nestedMap.set('test', new NestedClass(42));
const nestedMapWithArray = new Map<string, NestedClass[]>();
nestedMapWithArray.set('test', [new NestedClass(42)]);
const masterClass = new MasterClass(nestedMap, nestedMapWithArray);
const errors = await validator.validate(masterClass);
function expectNestedError(property: string) {
const nestedError = errors.find(error => error.property === property);
expect(nestedError).toBeDefined();
expect(nestedError).toMatchObject({ property, target: masterClass, });
}
expectNestedError('nestedMap');
expectNestedError('nestedWithArray');
});
});
});
Thanks
https://github.com/typestack/class-validator/pull/539 fixed multi-dimensional arrays for @ValidatedNested
. But we should also support multi-dimensional arrays for cases like:
@IsNumber({}, {
each: true
})
tags: number[][];
Note: I see one edge case here. What if I want to validate only first, second, third, ..., ... level of multi-dimensional array? E.g.:
@IsArray({}, {
each: true
})
@IsNumber({ each: true })
tags: number[][][][][];
Maybe we should add an option maxDepth for this?
whats the status on the situation here? I'm facing a simple 2d numeric array validation issue here and this issue is on hold for over a year now because of a rather rare edge case whilst simple multi-dimensional array checks are already possible but not yet merged. Any way to get into this again?
mark
Any word on this? Can anyone suggest a workaround using custom validators that can do the needful? I need to validate multi dimensional arrays of various types, ie. enums, strings, numbers, objectids (mongodb)
Simple custom decorator example below.
This validates that the property:
- is an array
- each element is also an array
- each sub array has 3 entries
- each sub entry is a string
You can tweak this for your needs
import { registerDecorator } from 'class-validator';
export function PermissionsValidator() {
// eslint-disable-next-line @typescript-eslint/ban-types
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'permissions',
target: object.constructor,
propertyName: propertyName,
validator: {
validate(value: unknown) {
return (
Array.isArray(value) &&
value.length > 0 &&
value.every((row) => {
return (
Array.isArray(row) &&
row.length === 3 &&
row.every((cell) => typeof cell === 'string')
);
})
);
},
},
});
};
}