Как вызвать перегруженную функцию из универсального - PullRequest
0 голосов
/ 29 апреля 2020

Пусть у меня есть два интерфейса, которые имеют несколько общих полей, и другой интерфейс, который их обобщает:

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;
}

Теперь я хочу написать функцию, которая печатает экземпляр этих интерфейсов. Я решил использовать перегрузку:

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);
}

Затем я хочу написать функцию, которая печатает их массив:

function printAll<ElementType extends ICommon>(array: ElementType[]) {
    for (const element of array)
        printElement(element)
}

Однако это не работает:

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)

Поскольку ElementType рассматривается как ICommon экземпляр. Например, компилятор пытается выполнить обратное преобразование из ICommon в IFirst, и это, очевидно, недопустимо. Как сделать этот тип функции безопасным тогда?

1 Ответ

1 голос
/ 29 апреля 2020

Вы можете добиться того, что вам нужно, с помощью чего-то подобного:

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);
    }
}

И вы можете улучшить проверку типов с помощью соответствующих функций, как описано в Проверка типа интерфейса с помощью Typescript

...