Skip to content

feature: ability to @Transform absent properties in plainToInstance #1813

Open
@blended-bram

Description

@blended-bram

Description

There currently is no way to decorate a property with a factory to produce a value for that field.
Specifically, to fill a field that is absent based on other data inside the object.

While you might get around that to some extend with computed properties, but these properties are not mutable without some serious plumbing to enable that.

Example case:

class Subject {
  @Transform(({value}) => value ?? 0) // (1)
  field!: number;
}

const instance = plainToInstance(Subject, {}) // (2)

Here (1) provides a fallback value for a field should it be blank (present, but undefined / null).
But counterintutively, an absent field and undefined are treated as separate cases; which runs counter to most JS code which treats absent == undefined. Only the in operator would help you spot the difference normally, or inspecting the entries.

Proposed solution

Without breaking backwards compatibility; add a flag to @Transform that causes the transform to trigger if the field is absent. The value property of TransformFnParams would logically be undefined.

One might argue that this does not belong to Transform because there is no value to be transformed and that this should become a separate decorator. But this will create a rift where users must be aware of the obscure difference between {field: undefined} and {}.

Please extend @transform with an option flag that opts users into running the transform on absent fields.
The field is akin to the to{Class,Plain}Only options already available, as it controls in what scenarios the transform is applied. So the new option could be called fromAbsentAlso.

class User {
  id!: number;

  // 1. Avatar can be specified in the source.
  // 2. The fallback is constructed from sibling data.
  // 3. The instance field is mutable and not some convoluted computed property.
  @Transform(({ value, obj }) => value ?? `https://example.com/${obj.id}/avatar.png`, {fromAbsentAlso: true})
  avatar!: string;
}

With this @Transform is providing a fallback for absent data; that logically treats absent fields as if they were explicitly set to undefined

As a real-world example, we have need for this when parsing data from Sanity.io, where their asset (image/video) objects do not yet have a usable url property when retrieved. Instead you can generate the url by building it from the other fields in the object. This is where we want to automatically build the url when parsing the data structure, but the field url does not yet exist in the raw data we receive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    flag: needs discussionIssues which needs discussion before implementation.type: featureIssues related to new features.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions