Add support for consistent inheritance #2673
Replies: 5 comments
-
|
It would be great to get this longstanding issue resolved @kranners. The current state makes |
Beta Was this translation helpful? Give feedback.
-
|
@kranners Thanks for taking the initiative on this. We currently use our own fork of the library in production, mainly because the inheritance behaviour has been problematic and we wanted to avoid writing large amounts of workaround code. That is also why I have been keeping our fork up to date with the upstream repository. One point I would like to highlight is that approaches such as
I suspect that in many cases where inherited validators are ignored with Because of this, I believe validator inheritance should remain aligned with the rules of TypeScript class inheritance, including respecting the Liskov Substitution Principle. Deviating from these constraints could lead to inconsistencies between the type system and the validation behaviour. |
Beta Was this translation helpful? Give feedback.
-
|
Good point @rdubigny - didn't consider typing in the example :) Specifically the issue in our codebase is around optional vs required properties. For example: class Person {
@MinLength(1)
name!: string;
@IsOptional()
@Min(0)
driverLicenseId?: number;
}
class Driver extends Person {
@IsNotEmpty()
declare driverLicenseId: number;
}
// Should fail validation since there is no driverLicenseId set
const instance = new Driver();
instance.name = "Raphaël";
validate(instance).then((errors) => {
console.dir({ errors }, { depth: null });
});Here this logs out To work around this currently we are using a hack like: class Driver extends Person {
@ValidateIf(() => true)
@IsNotEmpty()
declare driverLicenseId: number;
}However, this now skips the |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for keeping discussion on this issue moving @kranners & @rdubigny. For my usage, I agree with @rdubigny that all validators should be inherited, but I also agree with @kranners that ideally there would be a way to disable I guess this could be done using class Base {
protected valueRequired() {
return false;
}
@ValidateIf((o) => o.valueRequired())
@IsString()
value?: string;
}
class Derived extends Base {
protected override valueRequired() {
return true;
}
}@rdubigny Have you faced a pattern like this in your usage of your fork? |
Beta Was this translation helpful? Give feedback.
-
|
Hey @braaar @NoNameProvided, it would be awesome if you two could have a little look here and at @rdubigny 's PR :) |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi 👋!
Would love to get thoughts and opinions on making the inheritance of validators consistent across class-validator.
Happy to put in some time and work to get a new PR going, or updating an existing one to fix this up :)
What the issue is
The documentation states:
As of June 2020, there has been an issue raised for some validation decorators not running when they are inherited down the line.
These two classes should apply both decorators:
However, in this case
Child.somePropertyonly appliesIsUppercase.Existing work
There is a PR as a fix for this since September 2022, however it is full of TODO comments, is not caught up to the main branch, and appears generally incomplete.
In November 2025, a new PR was made which uses the existing one, but with the TODO comments removed, the branch rebased and tidied up.
The most recent time a PR around this saw a significant commit was November 14, 2025. (Thanks for this ongoing work @rdubigny 😄)
There are commits as recent as a few days ago, but those are all merge commits to keep the branch up-to-date.
Proposal
I'm proposing that class-validator is consistent with what the documentation states, that is that all inherited validators will run on redefined properties.
With one caveat! That they are explicitly and completely ignored for usages where this behaviour is unwanted. I'd propose a
IgnoreInheritedValidatorsvalidator, which removes all inherited validators from a given property.For example:
Without this new validator, you would have to either create an otherwise unused
BaseMemberProfilewhich bothMemberProfileandPoliteMemberProfileextends from, or use one of a few hacks listed on the original issue.I think this makes a bit more sense than the existing similar suggestion to create an
@Off(IsNumber)or similar validator.What here would make the maintainers lives as easy as possible? A new PR? An extension to the existing PR?
Thanks!! 🐪
Beta Was this translation helpful? Give feedback.
All reactions