-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exclude/Expose decorator for properties in class inheritance #13
Comments
Hi, that's an interesting use case. Thanks for the thorough explanation! I see how Another solution (let's call it const IsUserId = () => (...args: [object, string]) => {
IsUUID("4")(...args)
JSONSchema({ description: `User's ID` })(...args)
}
// although we could write a neater function for composing decorators... and then building validation classes out of these decorators: class GetUserRequest {
@IsUserId()
id: string;
} maybe class GetUserRequest implements Pick<User, 'id'> {
@IsUserId()
id: string;
} Might turn out a bit verbose but at least the validators are only defined once and reusable. |
@epiphone the solution 3 looks cool, but when I try to create a class extending Pick, I get an error: TS2693: Pick only refers to a type, but is being used as a value here. If I just create a type: Then the swagger file I'm getting leaks of this type, the schema is not generated for it. Did you find any solution for that? Am I doing something wrong? |
Oh my bad, For yet another approach, |
@epiphone few feedback:
I've come out with a new solution much lighter. // inheritValidations.ts
import { getFromContainer, MetadataStorage } from 'class-validator';
import { ValidationMetadata } from 'class-validator/metadata/ValidationMetadata';
export type ClassConstructor<T> = new () => T;
function strEnum<T extends string>(o: T[]): { [P in T]: P } {
return o.reduce((res, key) => {
res[key] = key;
return res;
}, Object.create(null));
}
export function inheritValidations<T, P extends keyof T>(NewClass: Function,
BaseClass: ClassConstructor<T>,
properties: P[]) {
const propertiesObject = strEnum(properties);
getFromContainer(MetadataStorage).getTargetValidationMetadatas(BaseClass, null)
.filter(md => properties.includes(md.propertyName as any))
.forEach((md) => {
const validationMetadata = { ...md };
validationMetadata.target = NewClass;
getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(validationMetadata));
});
return NewClass as new (...args: any) => Pick<T, keyof typeof propertiesObject>;
} Now we can define all the validations on the // GetUserRequest.ts
export class GetUserRequest extends inheritValidations(class GetUserRequest {}, User, ['id']) {} |
Cool, nice work! That seems really handy. If you've the time to open a PR I'd be happy to merge it ;) |
I forgot to mention this requires |
Doesn't it work without |
I have 2 projects sharing some entities, and I'm trying to find a way to keep the validation consistent through all my application, and if possible, reuse part of the code instead of copying/pasting it.
My example
Classes needed
Create User API schemas
Change Email API schemas
As we can see, we keep copying/pasting all the validations and descriptions from class to class, so I'm trying to find a better way to reuse the code so that it is also easier to maintain.
Solution 1
I create a common class containing the "base" properties.
And then try to reuse the "base" class whenever possible
Solution 2
Create a base class describing all the fields with their validations.
And then extend it excluding or exposing fields
Solution 1
can be already implemented, even tho it will be hard to isolate the "common" properties when the app starts becoming big. i.e. if I introduce an UpdateUser API, probably I want to keep the email out of it, so I have to remove the email from theUserCommon
class.Solution 2
would be really flexible but I guess it is not supported currently by this library, right? Any chance to get this implemented?Do you have any feedback? or any smarter way to achieve this result?
The text was updated successfully, but these errors were encountered: