class-transformer icon indicating copy to clipboard operation
class-transformer copied to clipboard

fix: ExposeAll does not work with excludeExtraneousValues

Open johny1614 opened this issue 3 years ago • 30 comments

Description

Strategy 'exposeAll' does not work as expected with true excludeExtraneousValues flag. Actual behaviour is as all properties were not exposed.

Minimal code-snippet showcasing the problem

class Dog {
  name: string;
}
const plainDoggie = {
      name: 'Azor',
      surname: 'dogs does not have surnames :('
};
const doggie = plainToClass(Dog, plainDoggie, {
      strategy: 'exposeAll',
      excludeExtraneousValues: true
});
console.log('doggie', doggie);
// should be {name:'Azor'}, but is {} instead

StackBlitz example

Expected behavior

All properties are exposed. In above example doggie = {name: 'Azor'}

Actual behavior

Properties are not exposed. In above example doggie = {}

johny1614 avatar May 18 '21 11:05 johny1614

Sorry for disturbing. @NoNameProvided Could you plz have a look at this issue?

Option strategy: 'excludeAll' behave allmost the same as excludeExtraneousValues: true, is that by design?

image It seems like that keys are the same except isMap and ignoreDecorators

ImJoeHs avatar Jul 23 '21 13:07 ImJoeHs

@johny1614 @ImJoeHs I have the same issue. Did you find any solution?

mohsensaremi avatar Oct 10 '21 15:10 mohsensaremi

Same here, is there any solutions for this yet?

TheCoordinator avatar Nov 19 '21 14:11 TheCoordinator

Same here, is there any solutions for this yet?

you can use @Expose for each property that you wanna expose it

minhduc-1999 avatar Nov 19 '21 18:11 minhduc-1999

Yes that's the only way. Clear in the code screenshot that was sent.

TheCoordinator avatar Nov 19 '21 18:11 TheCoordinator

I feel that the property by default should respect the strategy. Don't really think it has much to do with @Expose decorator. Unless I'm missing something?

TheCoordinator avatar Nov 19 '21 18:11 TheCoordinator

strategy: 'exposeAll' is a strategy: it should mean that by default, everything is exposed. excludeExtraneousValues: true means if something outside the class is in the object, then remove it. The combination of these two options should logically be that you don't need to decorate anything in the class with @Expose because everything will be exposed, but extraneous values should be removed.

Thus, this is a bug.

xaphod avatar Dec 01 '21 22:12 xaphod

strategy: 'exposeAll' is a strategy: it should mean that by default, everything is exposed.

excludeExtraneousValues: true means if something outside the class is in the object, then remove it.

The combination of these two options should logically be that you don't need to decorate anything in the class with @Expose because everything will be exposed, but extraneous values should be removed.

Thus, this is a bug.

Yes! 👍

TheCoordinator avatar Dec 01 '21 22:12 TheCoordinator

I would like it to work this way, too. But afaik this is a limitation of how typescript is working. excludeExtraneousValues works by only allowing known properties to pass. The name property is not known at runtime, because it has no decorator. So without a @Expose decorator, the property is unknown and will be stripped.

However I'm wondering why class-transformer features both strategy as well as excludeExtraneousValues. As far as I understand, strategy=ExcludeAll works the same as excludeExtraneousValues=true.

jbjhjm avatar Feb 01 '22 11:02 jbjhjm

I would like it to work this way, too. But afaik this is a limitation of how typescript is working. excludeExtraneousValues works by only allowing known properties to pass. The name property is not known at runtime, because it has no decorator. So without a @expose decorator, the property is unknown and will be stripped.

However I'm wondering why class-transformer features both strategy as well as excludeExtraneousValues. As far as I understand, strategy=ExcludeAll works the same as excludeExtraneousValues=true.

exactly - This can basically be achieved but with 1 major issue - any properties that don't have any decorators on them (from this library) will not be known at run time, and as such will be removed. This will render this feature highly unreliable and confusing... Sadly, I can't see a way around that issue.

regevbr avatar Feb 21 '22 13:02 regevbr

Sorry for disturbing. @NoNameProvided Could you plz have a look at this issue?

Option strategy: 'excludeAll' behave allmost the same as excludeExtraneousValues: true, is that by design?

image It seems like that keys are the same except isMap and ignoreDecorators

Very off-topic, but what font is this? :)

CodingMeSwiftly avatar Mar 13 '22 11:03 CodingMeSwiftly

@CodingMeSwiftly

Very off-topic, but what font is this? :)

I believe FiraCode

Angelin01 avatar Mar 19 '22 13:03 Angelin01

Any news on this issue? This simple change could be very beneficial for a lot of users.

gterras avatar Aug 09 '22 16:08 gterras

I have the same issue here, any news?

patrick-bf avatar Aug 10 '22 13:08 patrick-bf

by the way i use plainToInstance, because it saids that plainToClass is deprecated

patrick-bf avatar Aug 10 '22 13:08 patrick-bf

@patrick-bf Check the changelog, plainToClass has been deprecated in 0.5.0, correct.

Also, as discussed above there is no solution for this issue because of typescript limits.

IMO this issue should be closed.

jbjhjm avatar Aug 10 '22 14:08 jbjhjm

Could a strategy that relies on @Type instead of @Expose be created? At least it would be beneficial in some cases where they are already present.

gterras avatar Aug 10 '22 16:08 gterras

Would it be an option to take metadata from other libraries like for example class-validator in to account to determine, wether a property is "known"? Or maybe implement a decorator like class-validators @Allow() which is basically a no-op just to make properties known to the metadata storage?

mptr avatar Apr 07 '23 11:04 mptr

So is the only way to expose all properties is to manually @Expose each? Or is there a better way now?

Hareloo avatar Aug 08 '23 17:08 Hareloo

I faced the same issue so I created an extension method to achieve the wanted behavior:

  1. Create a new TypeScript file 'transform.dto.ts'
import { plainToInstance } from 'class-transformer';
import { getMetadataStorage } from 'class-validator';

export function transformToDto<T>(DtoClass: new () => T, data: any): T {

    const metadataStorage = getMetadataStorage();
    const dtoMetadata = metadataStorage.getTargetValidationMetadatas(DtoClass, '', true, true);

    const dtoInstance = plainToInstance(DtoClass, data);

    // Extract the keys from the DTO class metadata
    const dtoKeys = dtoMetadata.map(meta => meta.propertyName);

    // Filter out fields not in the DTO
    return dtoKeys.reduce((filtered, key) => {
        filtered[key] = dtoInstance[key];
        return filtered;
    }, {} as T);
}
  1. Use it like this:

const myInstance = transformToDto(myDTO, myData);

tapava avatar Aug 27 '23 19:08 tapava

Any news on this issue?

mwanago avatar Nov 16 '23 02:11 mwanago

@mwanago We ended up adding expose to every field.

peshkov3 avatar Nov 24 '23 12:11 peshkov3

Could this problem be solved with https://www.typescriptlang.org/tsconfig#useDefineForClassFields ?

I've done a test using the Expose decorator at class level and I was able to get the class properties with Object.getOwnPropertyNames(new object())

jesusbarcenilla avatar Jan 19 '24 12:01 jesusbarcenilla

It has been 2 years and this has yet to be resolved.. Why?

Hareloo avatar Feb 22 '24 17:02 Hareloo

Yeah pleassseeee fix this

smichel-amiltone avatar Feb 23 '24 16:02 smichel-amiltone

I think it is a very basic requirement but a very very useful feature, for security, we don't want they call API with extra fields, and it should be filtered easily, but not decorate every field.

Thanks

yipianbaifan avatar Mar 19 '24 10:03 yipianbaifan

Would love to see this fixed. Currently have to add a whole lot of decorators to every DTO to avoid leaking data. This would avoid that by automatically removing anything that isn't a property of the DTO.

AlexStansfield avatar Mar 22 '24 07:03 AlexStansfield

Would also love to see this issue to be resolved!

fabiankaimer avatar Mar 27 '24 19:03 fabiankaimer