Skip to content
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

Cannot transform string to number #1672

Open
stad-nico opened this issue Jan 18, 2024 · 7 comments
Open

Cannot transform string to number #1672

stad-nico opened this issue Jan 18, 2024 · 7 comments
Assignees
Labels
type: fix Issues describing a broken feature.

Comments

@stad-nico
Copy link

stad-nico commented Jan 18, 2024

Description

Trying to convert number strings wont cast the type to number. This was supposed to be fixed in 0.2.2 (Issue #179)

Minimal code-snippet showcasing the problem

import { plainToClass } from "class-transformer";
import { IsDate } from "class-validator";
import "reflect-metadata";

export class T {
	@IsDate()
	number!: number;
}

const m = plainToClass(T, { number: "10" }, { enableImplicitConversion: true });
console.log(m); // -> T { number: "10" }

Expected behavior

console.log(m); // -> T { number: 10 }

Actual behavior

console.log(m); // -> T { number: "10" }

The workaround using @Type(() => Number) still works, however I expect number strings to be converted without additionally specifying the type.

Using

"dependencies": {
    "class-transformer": "^0.5.1",
    "class-validator": "^0.14.1",
    "reflect-metadata": "^0.2.1",
    "ts-node": "^10.9.2",
    "typescript": "^5.3.3"
  }
@stad-nico stad-nico added status: needs triage Issues which needs to be reproduced to be verified report. type: fix Issues describing a broken feature. labels Jan 18, 2024
@andylizf
Copy link

same question

@diffy0712
Copy link

It seems that there is some problem with the environment and not the class-transformer package.
The package will try to find the correct type if it has metadata information, which will be available at runtime using the reflect-metadata package.
In fact when the mentioned pull request was merged it contained tests for checking this behavior and they still pass when I ran them.

If you log the (Reflect as any).getMetadata( "design:type",T.prototype,"number"), it should have value [Function: Number], but it is undefined in some cases and then the package will default to the original type.

I have tested your code:

  • in a new vite project it did not work
  • in a vitest test it did not work
  • using only npx ts-node it did work for me though

I am not sure why it behaves differently in these cases yet.

@abouroubi
Copy link

Same error here

@diffy0712
Copy link

To note a few things:

  • type declaration is emitted only if some decorator is added to the property. (so you must add at least one decorator to have type declaration available!
  • The emitDecoratorMetadata in your tsconfig might not have any affect if you are transpiling your typescript code other than tsc (which will result in an empty metadata so reflect-metadata will not be able to say anything about your types) for example:
    • Babel in its docs states the following:
    • Vite uses esbuild by default which, will not treat types in typescript files
    • SWC can be used to emitDecoratorMetadata (I have tested and it worked as expected), but keep in mind that @vitejs/plugin-react-swc plugin for Vite does not support emitting decorators.

I think there are a few serious limitations to this feature unfortunately, which should be mentioned somewhere.

But in the example provided by @stad-nico I see ts-node as dependency, which should work. Do you use ts-node to run the example above or something else?
When I tried to run your example with the same dependencies using ts-node it worked as expected.

@abouroubi
Copy link

abouroubi commented Mar 26, 2024

This issue appeared recently in my code, without any changes in my parts.
It looks weird because here is the emitted code:

__decorate([
    (0, class_validator_1.IsNumber)(),
    __metadata("design:type", Number)
], User.prototype, "AGE", void 0);

But when i use this code:

const validatedUser = plainToClass(User, userJson, {
    enableImplicitConversion: true,
  });

the AGE property stays as String instead of being transformed to Number.

For the time being I'll add @Type(() => Number) as a workaround, if I can help with a reproduction repo I'll try to do it.

@diffy0712
Copy link

diffy0712 commented Mar 26, 2024

Could you checkout a commit from before when it supposadely worked and check if there has been any package-lock.json (or yarn, or pnpm whatever you use) updated?
It should work if no package has been changed since. what environment does this runs on? browser or server?
If you could provide an example which produces the snippet you mentioned it would be very good.

thank you:)

@PurpleTape
Copy link

Same with Vite and code:

import 'reflect-metadata';
import { plainToClass } from 'class-transformer';

class Entry {
    num: number;
}

console.log(plainToClass(Entry, { num: '5.00' }));

@diffy0712 diffy0712 self-assigned this May 5, 2024
@diffy0712 diffy0712 removed the status: needs triage Issues which needs to be reproduced to be verified report. label May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: fix Issues describing a broken feature.
Development

No branches or pull requests

5 participants