Skip to content

fix: plainToInstance with discriminated type union with no matching subTypes silently returns DTO #1762

Open
@Woodz

Description

@Woodz

Description

Minimal code-snippet showcasing the problem

import { Type, plainToClass } from "class-transformer";

export abstract class Photo {
  id: number;
  filename: string;

  abstract getTitle(): string;
}

export class Landscape extends Photo {
  panorama: boolean;

  getTitle(): string {
    return `Landscape ${this.id} ${this.filename} ${this.panorama}`;
  }
}

export class Portrait extends Photo {
  person: Person;

  getTitle(): string {
    return `Portrait ${this.id} ${this.filename} ${this.person}`;
  }
}

export class UnderWater extends Photo {
  depth: number;

  getTitle(): string {
    return `UnderWater ${this.id} ${this.filename} ${this.depth}`;
  }
}

export class Album {
  id: number;
  name: string;

  @Type(() => Photo, {
    discriminator: {
      property: "__type",
      subTypes: [
        { value: Landscape, name: "landscape" },
        { value: Portrait, name: "portrait" },
        { value: UnderWater, name: "underwater" }
      ]
    }
  })
  topPhoto: Landscape | Portrait | UnderWater;
}

const validJsonInput = {
  id: 1,
  name: "foo",
  topPhoto: {
    id: 9,
    filename: "cool_wale.jpg",
    depth: 1245,
    __type: "underwater"
  }
};
const validAlbum = plainToClass(Album, validJsonInput);
console.log(validAlbum.topPhoto.getTitle());

const invalidJsonInput = {
  id: 2,
  name: "bar",
  topPhoto: {
    id: 10,
    filename: "random.jpg",
    __type: "unknown type"
  }
};
const invalidAlbum = plainToInstance(Album, invalidJsonInput); // <-- I would expect this method to throw an error since `unknown type` does not match a discriminated subType
console.log(invalidAlbum.topPhoto.getTitle()); // <-- However, it returns `invalidAlbum`, but `topPhoto` is the original DTO so methods fail with `invalidAlbum.topPhoto.getTitle is not a function`

Repro sandbox: https://codesandbox.io/p/sandbox/class-transformer-x3mbz

Expected behavior

I expect plainToInstance to throw an error if the discriminator property had a value that didn't match any subtype

Actual behavior

It silently returns the original DTO

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: needs triageIssues which needs to be reproduced to be verified report.type: fixIssues describing a broken feature.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions