es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo mapear con la ayuda de Automapper (TypeScript) las entradas de un arreglo lleno de diferentes DTOs?

Estoy utilizando la biblioteca TypeScript “Automapper” en mi backend NestJS para convertir una respuesta de MongoDb/Mongoose a un DTO. Así es como se ve la respuesta:

{
  "_id": "mongo-object-id",
  "widgets": [
    {
      "id": "UUID",
      "type": "IMAGE",
      "zIndex": "0",
      "position": { "x": 1, "y": 2 },
      "pinned": false,
      "height": 500,
      "width": 1000
    },
    {
      "id": "UUID",
      "type": "CONVERSATION",
      "zIndex": "1",
      "position": { "x": 3, "y": 7 },
      "pinned": false,
      "participants": ["UUID1","UUID2"]
    }
  ]
}

Mi problema es que no sé cómo convertir las entradas del array “widgets” a diferentes DTOs (ImageDTO, ConversationDTO) basados en el atributo/discriminador “type”.

¿Cómo puedo resolver esto?

Actualmente estoy usando lo siguiente:

mapper.createMap(MeetingSpace, MeetingSpaceDto).forMember(
    (destination) => destination.widgets,
    mapWith(WidgetDto, Widget, (source) => source.widgets)
);

Pero tengo que encontrar una forma de mapear un “Widget” a un “ImageDto” o “ConversationDto” debido al “type”.

mapWith(ImageDto, Widget, (source) => source.widgets)
mapWith(ConversationDto, Widget, (source) => source.widgets)
Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para resolver este problema, puedes usar la función de herencia y mapeo discriminator en Automapper. Primero, crea una clase abstracta llamada WidgetDto que contenga todas las propiedades comunes para todos los tipos de widgets. Luego, crea dos subclases llamadas ImageDto y ConversationDto que hereden de WidgetDto y tengan sus propias propiedades específicas.

    Después de definir las clases DTO, puedes usar la función de mapeo discriminator para asignar el atributo “type” a la subclase DTO correcta.

    Aquí tienes un ejemplo de código para los mapeos:

    abstract class WidgetDto {
      id: string;
      type: string;
      zIndex: string;
      position: {
        x: number;
        y: number;
      };
      pinned: boolean;
    }
    
    class ImageDto extends WidgetDto {
      height: number;
      width: number;
    }
    
    class ConversationDto extends WidgetDto {
      participants: string[];
    }
    
    mapper.createMap(Widget, WidgetDto)
      .forMember("type", mapFrom(source => source.type))
      .forMember("id", mapFrom(source => source.id))
      .forMember("zIndex", mapFrom(source => source.zIndex))
      .forMember("position", mapFrom(source => source.position))
      .forMember("pinned", mapFrom(source => source.pinned))
      .forMember("discriminator", mapFrom(source => {
        switch (source.type) {
          case "IMAGE":
            return ImageDto;
          case "CONVERSATION":
            return ConversationDto;
          default:
            throw new Error("Unknown widget type");
        }
      }));
    
    mapper.createMap(MeetingSpace, MeetingSpaceDto)
      .forMember("widgets", mapWith(WidgetDto, Widget, source => source.widgets));
    

    En el ejemplo anterior, el primer mapeo crea una asignación entre el modelo Widget y la clase abstracta WidgetDto. Este mapeo incluye el uso de la función discriminator para asignar el atributo “type” a la subclase correcta.

    El segundo mapeo luego utiliza el primer mapeo para asignar la propiedad “widgets” de MeetingSpace a un array de tipos WidgetDto.

    Con estos mapeos en su lugar, Automapper debería poder asignar automáticamente cada Widget a la subclase DTO correcta según su atributo “type”.

Comments are closed.