Reputation: 6687
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?
Upvotes: 0
Views: 37
Reputation: 858
You can achieve the kind of thing you're looking for with something like this:
interface IFirst {
common: "A" | "B";
private_0: string;
}
interface ISecond {
common: "C" | "D";
private_1: string;
}
type ICommon = IFirst | ISecond;
function printElement(element: ICommon) : void {
console.log(element.common);
if ("private_0" in element) {
console.log(element.private_0);
}
if ("private_1" in element) {
console.log(element.private_1);
}
}
function printAll(array: ICommon[]) {
for (const element of array) {
printElement(element);
}
}
And you can improve the type checking with proper functions as described in Interface type check with Typescript
Upvotes: 1