There is a function called polymorficFactory that creates instances of classes based on a provided 'discriminator' property:
type ClassConstructor<T> = {
new (...args: any[]): T;
};
type ClassMap<T> = Record<string, ClassConstructor<T>>;
function polymorficFactory<T extends object>(
classMap: ClassMap<T>,
discriminator: string,
input: Record<string, any>,
): T {
if (!input[discriminator]) throw new Error('Input does not have a discriminator property');
const discriminatorValue = input[discriminator];
const constructor = classMap[discriminatorValue];
return plainToInstance(constructor, input); // class-transformer util
}
This function is useful for handling unknown objects from request payloads:
const MOCK_PAYLOAD = {
type: 'SOME_DTO',
someProperty: 1,
someStr: 'Lorem',
someNestedProp: {
someBool: true,
}
} as as Record<string, unknown>; // Record<string, unknown/any>, since comes from JSON payload, but will always be an object
const dto = polymorficFactory<SomeDto | SomeOtherDto>(
{
SOME_DTO: SomeDto,
SOME_OTHER_DTO: SomeOtherDto,
},
'type',
MOCK_PAYLOAD ,
);
dto; // when hovering, type will be "SomeDto | SomeOtherDto"
If type parameters are not provided:
const dto = polymorficFactory(
...
);
dto; // when hovering, type will be "SomeDto"
The function selects the first value it finds in the provided object:
{
SOME_DTO: SomeDto,
SOME_OTHER_DTO: SomeOtherDto,
}
Is there a way to infer the union type, SomeDto | SomeOtherDto
or any other Dto classes from the map values, without explicitly specifying it?
For example, with this classMap:
{
A: aDto,
B: bDto,
C: cDto,
}
The expected inferred union type for the result would be:
aDto | bDto | cDto