You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中判断ExpoPushTicket存在id属性的正确方法

Expo Push Ticket类型判断问题解决方法

问题场景

现有TypeScript代码片段:

const tickets: ExpoPushTicket[] = [], receiptIds = [];

...

for (const ticket of tickets) {
  if (ticket.id) {
    receiptIds.push(ticket.id);
  }
}

expo-server-sdk的类型定义如下:

export declare type ExpoPushSuccessTicket = {
    status: 'ok';
    id: ExpoPushReceiptId;
};
export declare type ExpoPushErrorTicket = ExpoPushErrorReceipt;
export declare type ExpoPushErrorReceipt = {
    status: 'error';
    message: string;
    details?: {
        error?: 'DeviceNotRegistered' | 'InvalidCredentials' | 'MessageTooBig' | 'MessageRateExceeded';
    };
    __debug?: any;
};
export declare type ExpoPushTicket = ExpoPushSuccessTicket | ExpoPushErrorTicket;

编写时if (ticket.id)会触发编译错误:Property 'id' does not exist on type 'ExpoPushTicket'。尝试用Object.prototype.hasOwnProperty判断后,if语句无错误,但receiptIds.push(ticket.id)仍报错,需找到正确的属性判断方式,同时确认是否需要修改ExpoPushTicket类型。

解决方案

1. 通过status字段做类型收窄(推荐)

ExpoPushSuccessTicket和ExpoPushErrorTicket有明确的status区分值,直接判断该字段即可让TypeScript自动收窄类型:

for (const ticket of tickets) {
  if (ticket.status === 'ok') {
    receiptIds.push(ticket.id); // 此处ticket会被推断为ExpoPushSuccessTicket,无编译错误
  }
}

这种方式完全贴合库的类型设计,无需修改原有类型定义。

2. 自定义类型守卫函数(复用场景)

如果需要在多处判断票据类型,可以封装自定义类型守卫:

function isSuccessTicket(ticket: ExpoPushTicket): ticket is ExpoPushSuccessTicket {
  return ticket.status === 'ok';
}

// 使用示例
for (const ticket of tickets) {
  if (isSuccessTicket(ticket)) {
    receiptIds.push(ticket.id);
  }
}

是否需要修改ExpoPushTicket类型?

不需要。当前联合类型的设计逻辑合理:id仅属于成功场景的票据,失败票据不存在该属性。通过status字段做类型收窄,既符合业务逻辑,也能让TypeScript正确识别类型。

内容的提问来源于stack exchange,提问作者The Blind Hawk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 20:05:17