Subtyping

Mapping concrete types from its base mapping type.

Let's take a source base type Entity, two its subtypes (FooEntity, BarEntity), for a destination take a base class Dto and two its subtypes (FooDto, BarDto). To create mapping that handles this polymorphic scenario, define a discriminator and register subtype mappings to the supertype via mapSubtype.

class Entity {
    readonly discriminator: string;
    createdAt: string;
    property: string;
}

class FooEntity extends Entity {
    readonly discriminator = 'Foo';
}

class BarEntity extends Entity {
    readonly discriminator = 'Bar';
}

class Dto {
    property: string;
    createdAt: string;
}

class FooDto extends Dto {
    fooProperty: number;
}

class BarDto extends Dto {
    barProperty: number;
}

Setup mapping pairs for types above.

const EntityToDto = new MappingPair(Entity, Dto);

// "private" concrete mapping pairs
const FooEntityToDto = new MappingPair(FooEntity, FooDto);
const BarEntityToDto = new MappingPair(BarEntity, BarDto);

Register subtypes to the base type map via mapSubtype. Subtype map automatically inherits from its base so there is no need to explicitly define base/subtypes via includeBase or include.

For the discriminator we simply use read only property discriminator that is defined on both source subtypes. We can also exclude this property from mapping to the destination object.

const mapper = new MapperConfiguration(cfg => {
    cfg.createAutoMap(EntityToDto, {
        createdAt: opt => opt.mapFrom(src => '3020-01-01'),
    })
        .forSourceMember('discriminator', opt => opt.ignore())
        .mapSubtype(FooEntityToDto, src => src.discriminator === 'Foo')
        .mapSubtype(BarEntityToDto, src => src.discriminator === 'Bar');

    cfg.createAutoMap(FooEntityToDto, {
        fooProperty: opt => opt.mapFrom(src => parseInt(src.property))
    });

    cfg.createAutoMap(BarEntityToDto, {
        barProperty: opt => opt.mapFrom(src => parseInt(src.property))
    });
}).createMapper();

Perform mapping against the base mapping token EntityToDto.

const fooSource = new FooEntity();
fooSource.property = '123';
fooSource.createdAt = '2020-01-01';

const foo = mapper.map(EntityToDto, fooSource) as FooDto;
// "foo" is instance of "FooDto" and have following properties:
// {
//     property: '123',
//     fooProperty: 123,
//     createdAt: '3020-01-01'
// }

const barSource = new BarEntity();
barSource.property = '123';
barSource.createdAt = '2020-01-01';

const bar = mapper.map(EntityToDto, barSource) as BarDto;
// "bar" is instance of "BarDto" and have following properties:
// {
//     property: '123',
//     barProperty: 123,
//     createdAt: '3020-01-01'
// }

Last updated