Let I have two interfaces that have a few fields in common and another interfaces that generalizes them:
interface IFirst {
common: "A" | "B";
private_0: string;
}
interface ISecond {
common: "C" | "D";
private_1: string;
}
interface ICommon {
common: string;
private_0?: string;
private_1?: string;
}
Now, I want to write a function that prints an instance of these interfaces. I decided to use overloading:
function printElement(element: IFirst) : void;
function printElement(element: ISecond): void;
function printElement(element: ICommon) : void {
console.log(element.common);
if (element.private_0)
console.log(element.private_0);
if (element.private_1)
console.log(element.private_1);
}
Then I want to write a function that prints an array of them:
function printAll<ElementType extends ICommon>(array: ElementType[]) {
for (const element of array)
printElement(element)
}
However, this doesn't work:
No overload matches this call. Overload 1 of 2, '(element: IFirst): void', gave the following error.
Argument of type 'ElementType' is not assignable to parameter of type 'IFirst'.
Type 'ICommon' is not assignable to type 'IFirst'.
Types of property 'common' are incompatible.
Type 'string' is not assignable to type '"A" | "B"'. Overload 2 of 2, '(element: ISecond): void', gave the following error.
Argument of type 'ElementType' is not assignable to parameter of type 'ISecond'.
Type 'ICommon' is not assignable to type 'ISecond'.
Types of property 'common' are incompatible.
Type 'string' is not assignable to type '"C" | "D"'.(2769)
Because ElementType
is considered as ICommon
instance. The compiler tries to do a backwards conversion from ICommon
to IFirst
, for example, and it is obviously illegal. How do I make this function type safe then?