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

Exposed "getters only" don't get handled in plainToInstance #1807

Open
KikoCosmetics opened this issue Jan 11, 2025 · 3 comments
Open

Exposed "getters only" don't get handled in plainToInstance #1807

KikoCosmetics opened this issue Jan 11, 2025 · 3 comments
Labels
status: needs triage Issues which needs to be reproduced to be verified report. type: fix Issues describing a broken feature.

Comments

@KikoCosmetics
Copy link

KikoCosmetics commented Jan 11, 2025

Description

It seems that using plainToInstance where you have a few getters (without setters) doesn't work.
I have this recollection where I converted responses in Angular and this used to work.
But I tried up to class-transformer 0.4.0 and it always behaves the same.

This is somewhat related (or clones) #1257

class ErrorResponse {
    @Expose()
    get errorCode(): number {
        return this._errorCode;
    }

    constructor(protected _errorCode: number = 800){}
}

plainToInstance(ErrorResponse, {
   "errorCode": 123
});

Blitz with full code here => https://stackblitz.com/edit/ts-class-transformer-issue

Expected behavior

I would expect to have

{
errorCode: 123
}

Actual behavior

{
errorCode: 800
}

@KikoCosmetics KikoCosmetics added status: needs triage Issues which needs to be reproduced to be verified report. type: fix Issues describing a broken feature. labels Jan 11, 2025
@mezozawahra
Copy link

Typescript considers properties that have just get accessor to be readonly properties, so you can't set it
I think adding setter would solve it, like this:

class ErrorResponse {
    @Expose()
    get errorCode(): number {
        return this._errorCode;
    }
    set errorCode(value: number): number {
        this._errorCode = value;
    } 

    constructor(protected _errorCode: number = 800){}
}

plainToInstance(ErrorResponse, {
   "errorCode": 123
});

@KikoCosmetics
Copy link
Author

@mezozawahra yeah man, I know. That's why I said "without getters".
Also if you open the blitz, there is the example with the setters and it works.

The fact is that I'm almost sure I used to do this before and it worked.

I should still have the project where I used to do this. I'll update here in case.

In any case there could be a way of marking the getter protected property to overcome this without adding a setter.

For example

class ErrorResponse {
    @Expose()
    @SerializeTo("_errorCode")
    get errorCode(): number {
        return this._errorCode;
    }
    set errorCode(value: number): number {
        this._errorCode = value;
    } 

    constructor(protected _errorCode: number = 800){}
}

That would allow keeping the member readonly.

@tonysamperi
Copy link

Cool workaound though: having a custom method to deserialize...
It would be cool if plainToInstance managed this automagically...
But in the meantime this generates the instance while preserving the readonly members

class SimpleError {
  @Expose()
  get errorCode(): number {
      return this._errorCode;
  }

  constructor(protected _errorCode: number = 800){}

  static fromPlain(plain: any): SimpleError {
    // Classe di passaggio che aggiunge i setter
    class SimpleErrorMutable extends SimpleError {
      set errorCode(value: number) {
        this._errorCode = value;
      }
    }

    // Deserializziamo in SimpleErrorMutable
    const tempInstance = plainToInstance(SimpleErrorMutable, plain, {
      excludePrefixes: ["_"],
      excludeExtraneousValues: !0
    });

    // Creiamo una vera istanza della classe base
    const instance = new SimpleError();

    // Copiamo tutti i membri da tempInstance a instance
    Object.getOwnPropertyNames(tempInstance).forEach((key) => {
      if (key in instance) {
        (instance as any)[key] = (tempInstance as any)[key];
      }
    });

    return instance;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: needs triage Issues which needs to be reproduced to be verified report. type: fix Issues describing a broken feature.
Development

No branches or pull requests

3 participants