访问打字稿联合类型中的不同属性

Accessing different properties in a typescript union type

我正在创建一个函数来处理数据库中的对象。我有两个不同的数据结构,其中相同的 属性 具有不同的名称。我无法更改它,所以我必须在 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; 都标记为错误 ("Property does not exist on type"),因为这两种类型不具有两个属性。

那么,正确的打字稿方式是什么?

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

您需要创建一个用户定义的类型保护,然后您可以使用 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;
}

看看here。项目已正确转换为 TypeA 或 TypeB。

如果您不经常这样做,您可以进行类型断言:

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

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

如果您需要多次进行此检查,最好按照@Daryl 的建议编写一个类型保护。

使用typeguards:

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

我不会把事情复杂化。如果您真的确定您的对象具有一个或另一个 属性,那么 name = item['itemName'] || item['itemTitle']name = item.hasOwnProperty('itemName') ? item['itemName'] : item['itemTitle'] 就足够了。

请注意,如果您使用括号表示法而不是点表示法访问属性,TypeScript 通常会停止报错。不过,我建议添加评论。

我可能来晚了一点,但你可以在你的函数中试一试:

if ('itemName' in item) {
    name = item.itemName;
} else {
    name = item.itemTitle;
}
interface TypeA {
  a: string
}
interface TypeB {
  b: string
}

const testFunction = (x: TypeA | TypeB): string => {
  return (x as TypeA).a || (x as TypeB).b;
}

testFunction({ a: 'Hello' }); // 'Hello'
testFunction({ b: 'World' }); // 'World'