Reputation: 301
Imagine I have these interfaces:
interface FirstElement {
id: string;
coordinates: Coordinates;
type: FirstElementTypes;
options: FirstElementOptions;
}
interface SecondElement {
id: string;
coordinates: Coordinates;
type: SecondElementTypes;
options: SecondElementOptions;
}
interface FirstElementDTO {
id: string;
type: FirstElemenTypes;
options: FirstElementOptions;
}
interface SecondElementDTO {
id: string;
type: SecondElementTypes;
options: SecondElementOptions;
}
Now I want to create a DTO object, mapping these interfaces to their corresponding DTO interface. Because they share the same properties, with only the options being different, I'd like to use a single converter function. But when using typescripts union typing like this...
private static convertElementToDTO(element: FirstElement | SecondElement): FirstElementDTO | SecondElementDTO {
return {
id: element.id,
options: element.options,
type: element.type
};
}
...I (obviously) get an error message telling me that the options are not compatible. Would it be possible in typescript to "tell" a function that if FirstElement
is the input type, FirstElementDTO
is the output type and vice versa for SecondElement
- without writing the same code multiple times and using several if-statements? Thanks for your help!
Upvotes: 1
Views: 692
Reputation: 327774
It's possible a generic function might work here. First, some dummy type definitions to make the code here a self-contained example:
type FirstElementTypes = { FirstElementTypes: true };
type FirstElementOptions = { FirstElementOptions: true };
type SecondElementTypes = { SecondElementTypes: true };
type SecondElementOptions = { SecondElementOptions: true };
Then we can represent your types this way, to reduce code duplication:
// your types
interface FirstElementDTO {
id: string;
type: FirstElementTypes;
options: FirstElementOptions;
}
interface SecondElementDTO {
id: string;
type: SecondElementTypes;
options: SecondElementOptions;
}
// define elements as extension of DTOs to reduce code duplication
interface FirstElement extends FirstElementDTO {
coordinates: Coordinates;
}
interface SecondElement extends SecondElementDTO {
coordinates: Coordinates;
}
And finally here's the generic function:
// generic Pick function
function convertElementToDTO<E extends FirstElement | SecondElement>(
element: E
): Pick<E, "id" | "options" | "type"> {
return {
id: element.id,
options: element.options,
type: element.type
};
}
And it works without error:
declare const f: FirstElementTypes;
declare const o: FirstElementOptions;
declare const c: Coordinates;
const first: FirstElementDTO = convertElementToDTO({
id: "firstEl",
type: f,
coordinates: c,
options: o
}); // okay
Hope that helps; good luck!
Upvotes: 2