Skip to content

Cannot transform string to number #1672

Open
@stad-nico

Description

@stad-nico

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"
  }

Activity

added
status: needs triageIssues which needs to be reproduced to be verified report.
type: fixIssues describing a broken feature.
on Jan 18, 2024
andylizf

andylizf commented on Mar 22, 2024

@andylizf

same question

diffy0712

diffy0712 commented on Mar 24, 2024

@diffy0712

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

abouroubi commented on Mar 25, 2024

@abouroubi

Same error here

diffy0712

diffy0712 commented on Mar 25, 2024

@diffy0712

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

abouroubi commented on Mar 26, 2024

@abouroubi

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

diffy0712 commented on Mar 26, 2024

@diffy0712

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

PurpleTape commented on Apr 4, 2024

@PurpleTape

Same with Vite and code:

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

class Entry {
    num: number;
}

console.log(plainToClass(Entry, { num: '5.00' }));
self-assigned this
on May 5, 2024
removed their assignment
on Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: fixIssues describing a broken feature.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @PurpleTape@abouroubi@andylizf@diffy0712@stad-nico

        Issue actions

          Cannot transform string to number · Issue #1672 · typestack/class-transformer