-
Notifications
You must be signed in to change notification settings - Fork 509
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
fix: npm linking from a package that uses class-transformer breaks decorators #1043
Comments
Hi, Take a look at this issue. I've added your class to my package index.ts and in my tsc-app, index.ts I've added: import { ..., BaseClass } from 'tsc-package/dist'
export class ExtendedClass extends BaseClass { }
const a = new ExtendedClass()
a.someProperty = 'not actually exposed'
console.log(plainToClass(ExtendedClass, a)) // results in ExtendedClass { someProperty: 'not actually exposed' } Take a look at my setup and compare, for example, I didn't install the package with link. I made EDIT: |
Hi! I have the same issue. Is someone have a workaround? Thanks, |
I have a similar setup where I put all the I was able to get things working with following steps:
Then it starts to work for me |
i face the same issue. we're currently building a nestjs backend with microservices. we have to have the same dto's in the service and the gateway. this is blocking our current implementation from validating number inputs in queries. i'd gladly help with a pr, but i have no experience with oss and don't know how this package works. |
I'm having the same issue, I'm using packages inside a monorepo, although @WangHansen workaround works for me, the problem is that I'm using nestjs, and version 0.4.0 breaks with it |
Same issue here. |
I resolved my issue by doing the following; When linking an npm package from my project, I add the following to my project's webpack config:
This ensures that my library resolves the same instances than my project for both these packages and fixes the decorator issues. The issue seem to be caused by the fact that when linking a library, I develop the library locally and have a node_modules folder. From my project build, the library still resolves packages from the library's node_modules which seem to cause issues with class-transformer. |
@jonasschultheiss I was faced the same situation as you. I could solve it by setting all class-transformer installations (lib and microservices) to the exactly same version. If you do so, npm will collapse them into one folder (node_modules/class-transformer) instead of multiple installation in different subfolders (eg node_modules/my-lib/transformer, node_modules/my-service/transformer). It works because the metadata of the decorators are stored in this folder. If you have multiple class-transformer folders within the node_module and its subdirectories, it can't find the right one. |
I encountered the same issue in a different context. As part of these types, they copy In my own code, I import decorators directly from I don't know why exactly the modules resolve the way they do, and why tsc behaves differently than webpack, but it's probably a combination of the weird hacky import of
Anyways, if anyone else encounters the same problem, I managed to find a workaround using @Quovadisqc's comment above with some adjustments. {
'class-transformer/cjs/storage': path.resolve('./node_modules/class-transformer/cjs/storage'),
'class-transformer': path.resolve('./node_modules/class-transformer/cjs'),
} This forces all imports of |
Never mind, my issue was caused by something different. |
{
'class-transformer/cjs/storage': path.resolve('./node_modules/class-transformer/cjs/storage'),
'class-transformer': path.resolve('./node_modules/class-transformer/cjs'),
} you saved 2 days of my life. |
After going through the suggested solutions in this thread, I decided not to use the webpack approach to resolve the issue. Instead, I exposed a custom transformerPackage from the shared package folder and used it in the ValidationPipe in the Nestjs project. In the import { ClassTransformer } from 'class-transformer';
const transformer = new ClassTransformer();
// map classToPlain and plainToClass since they are renamed in class-validator
// but Nestjs still expects them.
const transformerPackage = {
classToPlain: transformer.instanceToPlain,
plainToClass: transformer.plainToInstance,
};
export { transformerPackage }; In the import { transformerPackage } from 'shared-folder';
...
app.useGlobalPipes(
new ValidationPipe({
transform: true,
transformerPackage,
}),
);
... This approach prevents you from having to tinker with the build steps of Nestjs and preserves the metadata of the used class-transformer instances. |
you saved 3 days of my life. |
Nestjs changed the necessary functions in version 11 : export interface TransformerPackage {
plainToInstance<T>(
cls: Type<T>,
plain: unknown,
options?: ClassTransformOptions,
): T | T[];
classToPlain(
object: unknown,
options?: ClassTransformOptions,
): Record<string, any> | Record<string, any>[];
} You should now put this instead : import { ClassTransformer } from 'class-transformer';
const transformer = new ClassTransformer();
// map classToPlain and plainToInstance since they are renamed in class-validator
// but Nestjs still expects them.
const transformerPackage = {
classToPlain: transformer.instanceToPlain,
plainToInstance: transformer.plainToInstance,
};
export { transformerPackage }; |
Description
Using
@Type
,@Transform
and@Expose
decorators in a linked package (npm link
in development environment) and extending classes from the linked package nullifies the decorators on the extended class. This probably applies to other decorators as well.class-transformer
is a peer dependency of my linked package. The linked package also includes theclass-transformer
in its node_modules (so I cannpm run build:watch
). The issue arises due to the fact that the metadata storage won't be shared between the two (my app and my linked package) - a workaround is tonpm link
class-transformer from my app and thennpm link class-transformer
from my linked package but this is a little hacky and probably fragile.class-validator
uses the global mechanism for metadata storage and I would propose using that forclass-transformer
as well. See https://github.com/typestack/class-validator/blob/4e39a04fd966782aa8ee7f2d56bdbdb05c956469/src/metadata/MetadataStorage.ts#L144-L152Minimal code-snippet showcasing the problem
Linked npm package:
Main app:
Expected behavior
Expected
someProperty
to be included in theplainToClass
transformation.Actual behavior
someProperty
is not copied over to the new instance ofExtendedClass
.The text was updated successfully, but these errors were encountered: