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

Transforming objects created by Object.create(null) produce unexpected results. #120

Closed
blaugold opened this issue Jan 3, 2018 · 6 comments
Labels
status: done/released Issue has been completed, no further action is needed. type: fix Issues describing a broken feature.

Comments

@blaugold
Copy link

blaugold commented Jan 3, 2018

When transforming a plain object created by Object.create(null) plainToClass does not return a new instance of the given constructor. Instead, it returns the original object:

import { plainToClass } from 'class-transformer'

class A {

  a: string

}

function initObject(o: any): any {
  o.a = 'A'
  return o
}


const objectWithoutPrototype = Object.create(null)
const object                 = {}

const instanceFromObject                 = plainToClass(A, initObject(object))
const instanceFromObjectWithoutPrototype = plainToClass(A, initObject(objectWithoutPrototype))

printInstance('instanceFromObject', instanceFromObject)
printInstance('instanceFromObjectWithoutPrototype', instanceFromObjectWithoutPrototype)

console.log('instanceFromObjectWithoutPrototype === objectWithoutPrototype',
  instanceFromObjectWithoutPrototype === objectWithoutPrototype)

function printInstance(name: string, inst: any) {
  const prototype   = Object.getPrototypeOf(inst)
  const constructor = prototype && prototype.constructor

  console.log(`${name}:`)
  console.log('prototype', prototype)
  console.log('constructor', constructor && constructor.name)
  console.log('instance', inst)
  console.log('')
}

When exectued:

instanceFromObject:
prototype A {}
constructor A
instance A { a: 'A' }

instanceFromObjectWithoutPrototype:
prototype null
constructor null
instance { a: 'A' }

instanceFromObjectWithoutPrototype === objectWithoutPrototype true

"class-transformer": "^0.1.8"

@bjyoungblood
Copy link

👍 here. Apparently the Express.js team decided that it's best for user-supplied objects to have a null prototype (see links below). Unfortunately, this means that instanceof Object checks will fail on these objects.

expressjs/multer#187
expressjs/discussions#25
expressjs/multer#318

The culprit is here.

The simplest fix would be to add || typeof value === 'object' to the condition.

As for the potential for future debugging, my personal preference would be to throw an error from the else case of TransformOperationExecutor::transform instead of returning the original value, especially since returning the original value violates the return type contract defined by plainToClass.

@blaugold
Copy link
Author

I stumbled across this issue because GraphQL does the same.

@NoNameProvided
Copy link
Member

Thanks for the heads up @bjyoungblood!

This looks serious. Can you propose a PR with your minimal fix for this?

@NoNameProvided
Copy link
Member

This has been fixed in 0cd39ed and will be included in the next release.

@NoNameProvided NoNameProvided reopened this Feb 4, 2018
@NoNameProvided NoNameProvided added the status: fixed Issues with merged PRs, but not released yet label Feb 4, 2018
@NoNameProvided
Copy link
Member

Just published 0.1.9, please test it and report if you still encounter this issue. Thanks!

@github-actions
Copy link

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.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 31, 2020
@NoNameProvided NoNameProvided added status: done/released Issue has been completed, no further action is needed. type: fix Issues describing a broken feature. and removed status: fixed Issues with merged PRs, but not released yet labels Jan 14, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status: done/released Issue has been completed, no further action is needed. type: fix Issues describing a broken feature.
Development

No branches or pull requests

3 participants