typestack/class-transformer

feature: @Expose toInstanceOnly

samislam opened this issue ยท 3 comments

Description

๐Ÿ’ก I'll start by writing the problem, then I'll provide the solution.

I have this class:

class A {
  description: string
}

I want when creating an instance from this class to normally call description in order to set it.
But when accessing the class instance, I want it to become a.desc.

Normally, you'd do something like this:

class A {
  desc: string
  constructor(description: string) {
    this.desc = description
  }
}
const instance = new A("xxx xxx xxx")
console.log(instance) // { desc: "xxx xxx xxx" }

I was thinking, can I do something like this?

class A {
  @RenameKey("desc")
  description: string
}

I found the @Expose() decorator, but it changes the input and output property name, I want the property name of the input to be description normally, but the output should be desc.

I know I can do this:

const a = new A("xxx xxx xxx")
a.desc = a.description
delete a.description

But I want to achieve this using decorators.

So I found the solution but it requires an extra step.

// 1. You have to set the toPlainOnly
class A {
 @Expose({ name: 'desc', toPlainOnly: true })
  description: string
}
// 2. create an instance
const x = plainToInstance(A, { description: "xxx xxx xxx" })
// 3. return the instance back to plain object
const y = instanceToPlain(x, {})
console.log(y) // { desc: "xxx xxx xxx" } โœ… works!

Proposed solution

I suggest a shortcut to the steps in the solution above by implementing a forInstanceOnly option as follows:

class A {
 @Expose({ name: 'desc', toInstanceOnly: true }) // ๐Ÿ‘ˆ here! ๐Ÿ’ก
  description: string
}

I answered this on Stack Overflow:

https://stackoverflow.com/a/78767062/18387350

Also I wanted to point out that this is different from toClassOnly because I tried this and I got undefined

class A {
        @Expose({ name: 'desc', toClassOnly: true })
        description: string
      }
      const x = plainToInstance(A, { description: 'xxx xxx xxx' })
      console.log(x) // A { description: undefined } โŒ doesn't work!

This is because in order to set the description property, you'll have to write desc and not description. And this is different from what my toInstanceOnly does.

Hello @samislam,

The code above works as expected. You've the option toClassOnly on your expose and you provide description in your plain, but you configured it to wait desc. The Expose decorator contains the necessary renaming for toPlainOnly and toClassOnly.

I close this issue as invalid.

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.