Доступ к различным свойствам в типе объединения машинописного текста

Я создаю функцию, которая обрабатывает объекты из базы данных. У меня есть две разные структуры данных, в которых одно и то же свойство имеет другое имя. Я не могу это изменить, поэтому мне приходится обрабатывать это в JavaScript.
У объектов есть другие отличия, но это не важно для этой функции.
Я хочу использовать одну и ту же функцию для двух разных типов объектов. Вот пример кода, демонстрирующий мою проблему:

interface TypeA {
    itemName: string;
}

interface TypeB {
    itemTitle: string;
}

function getItemName(item: TypeA | TypeB): string {
    let name = '';

    if (item.hasOwnProperty('itemName')) {
        name = item.itemName;
    } else {
        name = item.itemTitle;
    }

    return name;
}

Конечно, этот код работает. Но IDE отмечает обе строки name = item.itemName; и name = item.itemTitle; как ошибки («Свойство не существует для типа»), потому что оба типа не имеют обоих свойств.

Итак, как это сделать с помощью машинописного текста?


person KWeiss    schedule 19.04.2017    source источник


Ответы (6)


Вам нужно создать User Defined Type Guard, затем вы можете использовать оператор if и получить правильный ввод.

function isTypeA(value: TypeA | TypeB): value is TypeA {
    return value.hasOwnProperty('itemName');
}

Тогда вы сможете сделать набор текста намного чище:

function getItemName(item: TypeA | TypeB): string {
    return isTypeA(item) ? item.itemName : item.itemTitle;
}

Проверьте это здесь. Предмет правильно преобразован в TypeA или TypeB.

person Daryl    schedule 19.04.2017

вы можете сделать утверждение типа, если вы не делаете это слишком часто:

if (item.hasOwnProperty('itemName')) {
    name = (item as TypeA).itemName;
} else {
    name = (item as TypeB).itemTitle;
}

or

if (item.hasOwnProperty('itemName')) {
    name = (<TypeA>item).itemName;
} else {
    name = (<TypeB>item).itemTitle;
}

если вам нужно выполнить эту проверку более одного или двух раз, вам лучше написать защиту типа, как предлагает @Daryl.

person n00dl3    schedule 19.04.2017

Intellij принимает этот синтаксис:

function getItemName(item: TypeA): string;
function getItemName(item: TypeB): string;
function getItemName(item): string {
    return item.hasOwnProperty('itemName') ? item.itemName : item.itemTitle;
}

официальный способ в соответствии с документами машинописного текста следующий: https://www.typescriptlang.org/docs/handbook/functions.html

person Laurence Mommers    schedule 19.04.2017

Возможно, я немного опоздал, но вы можете попробовать это внутри своей функции:

if ('itemName' in item) {
    name = item.itemName;
} else {
    name = item.itemTitle;
}
person Ethelom    schedule 07.03.2021

Используйте typeguard:

interface TypeA {
    itemName: string;
}

interface TypeB {
    itemTitle: string;
}

function isTypeA(val: any): val is TypeA
{
    return val.hasOwnProperty('itemName');
}

function isTypeB(val: any): val is TypeB
{
    return val.hasOwnProperty('itemTitle');
}

function getItemName(item: TypeA | TypeB): string
{
    let name = '';

    if (isTypeA(item))
    {
        name = item.itemName;
    }
    else
    {
        name = item.itemTitle;
    }

    return name;
}
person Amid    schedule 19.04.2017

Не буду усложнять. Если вы действительно уверены, что ваш объект имеет то или иное свойство, достаточно name = item['itemName'] || item['itemTitle'] или name = item.hasOwnProperty('itemName') ? item['itemName'] : item['itemTitle'].

Обратите внимание, что TypeScript обычно перестает жаловаться, если вы обращаетесь к свойствам, используя обозначение скобок вместо обозначения точки. Я бы посоветовал добавить комментарий.

person SVSchmidt    schedule 19.04.2017