如何对Expense对象due属性的Timestamp|string联合类型进行类型收窄?
如何正确收窄Timestamp | string类型以访问seconds属性?
问题背景
从API获取Expense[]类型数组,其中Expense的due属性为Timestamp对象或string类型。需要从Timestamp对象中提取seconds属性并格式化为字符串展示,希望避免使用类型断言,尝试过in关键字和satisfies但未成功,当前代码依赖类型断言才能运行。
简化后的类型定义与代码:
interface Timestamp { seconds: number; nanoseconds: number; } interface Expense { name: string; amount: number; remaining: number; due: Timestamp | string; notes: string; category: string; } this.expenses = expenses.map((expense) => { if (typeof expense.due !== 'string') { return { ...expense, due: this.formatDate(expense.due.seconds * 1000) } as Expense; } }) as Expense[]; formatDate(milliseconds: number) { return new Intl.DateTimeFormat('en-ca', { weekday: 'short', day: 'numeric', year: 'numeric', }).format(new Date(milliseconds)); }
解决方案
你的核心思路没问题,typeof expense.due !== 'string'已经能正确将due收窄为Timestamp类型,问题出在**map函数缺少else分支的返回值**,导致TypeScript无法确定所有情况都返回Expense类型,才需要额外断言。修正方式如下:
修正后的代码
this.expenses = expenses.map((expense) => { // typeof判断已完成类型收窄,无需断言 if (typeof expense.due !== 'string') { return { ...expense, due: this.formatDate(expense.due.seconds * 1000) }; } // 补全else分支,返回原expense(或根据需求处理string类型的due) return expense; });
关键说明
- 补全返回分支:
map函数要求每个迭代都返回对应类型的值,原代码中当due是string时没有返回值,导致数组可能混入undefined,TypeScript只能通过断言强制类型。补全return expense后,TypeScript能自动推导出返回值为Expense类型,无需as Expense断言。 - typeof的有效性:
typeof expense.due !== 'string'可以准确排除string类型,剩下的自然是Timestamp类型,TypeScript会自动认可expense.due.seconds的访问。 - 替代收窄方式(可选):如果需要更明确的类型判断,也可以用
in关键字检查属性:if ('seconds' in expense.due) { // 此时due已收窄为Timestamp类型 return { ...expense, due: this.formatDate(expense.due.seconds * 1000) }; } return expense;
内容的提问来源于stack exchange,提问作者lowkey
相关产品推荐
相关产品推荐

