-
Notifications
You must be signed in to change notification settings - Fork 505
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
discussion: custom class constructor #132
Comments
I don't know any way to do that at the moment. |
newValue = Reflect.construct(Object, [], targetType); in TransformOperationExecutor.ts line 119 (and probably in other places where it creates objects using |
@NoNameProvided I see you removed the Is this change still open for discussion or would you be willing to accept a PR? We use a lot of custom constructors and we now use the following pattern to avoid constructor errors: class Test {
constructor(options: TestType) {
if (options) {
// ... do things with constructor values
}
} This is suboptimal. Changing the internals to not call the constructor would be a big improvement for our project, so I'll be willing to invest the time. |
Using the constructor to create an object in |
@axiac looking into this. There is only one place where However I'm running into some problems related to default properties. The repo recently had a PR merged that will keep default properties in the class. e.g.: class Test {
propertyWithDefaultValue = 10
} Because the constructor isn't called the default values aren't set. Would you know how to deal with this? Failing tests
|
Not calling the constructors is a breaking change. I'm sure it breaks the functionality of many programs that use this package. I would implement this change as an experimental feature that is disabled by default and can be enabled somehow by those who want to use it. This way it does not break the programs that use this package and can be released as a non-breaking new feature. From the semantic versioning point of view, this means an increase of the minor version. The default behaviour can be changed to not call the constructors on the next major version of the package (the breaking changes require increasing the major version). Calling the constructor should still be available on the next major version as an opt-in, to allow the users of the package to upgrade to the new version without forcing them to use this new breaking-change feature. Then, on the next major version (or after some time), the flag and the code that calls the constructors can be removed and the new behaviour becomes the only working way. This is usually the flow to implement such a breaking change while keeping the backward compatibility with the previous versions of the package and letting the users of the package some time to accommodate the change into their code. I recommend this approach because the changed behaviour is not visible in the interface of the package. The change is subtle and its effects might not be immediately visible. |
I agree we should do this behind a feature flag. However as the default property feature is already merged I can't see this ever being merged if default property values will be disposed. I'm gonna take another look. Thanks for the exhaustive answer! |
For anyone struggling right now: I don't know if my workaround is valid but currently I simply create a wrapper type and a custom transform (example with luxon): import { DateTime} from 'luxon';
export type DT = DateTime;
export function toDateTime(value: string | Date | DateTime): DateTime {
if (typeof value === 'string') return DateTime.fromISO(value);
if (value instanceof Date) return DateTime.fromJSDate(value);
if (value instanceof DateTime) return value;
throw new Error('Wrong entity type');
} Then I use this type and transform in my class: export class Meeting {
...
@Transform(value => toDateTime(value), { toClassOnly: true })
start: DT;
...
} I hope this helps someone. |
After thinking about this, nothing like this will be implemented. However, the desired behavior is easily achievable with import { Container } from 'typedi';
import { Transform } from 'class-transformer';
export class MyClass {
@Transform({ value } => Container.get(MyService).doSomeStuff(value))
someProperty!: any;
} |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
How should we handle situations where there are custom constructor for classes? E.g. if the class object I'm transforming into needs access to a database connection and I would like that to be passed into the constructor. Is it possible to still use plainToClass?
The text was updated successfully, but these errors were encountered: