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
相关产品推荐
相关产品推荐

