嵌套接口中Sum Types类型收窄失效的原因探究
TypeScript 联合类型嵌套标识无法收窄类型的原因
先看一个能正常运行的联合类型(Sum Types)示例:
interface Cash { amount: number, type: 'cash' } interface Card { amount: number, type: 'card', cardNumber: string } type Payment = Cash | Card const logPayment = (payment: Payment) => { if (payment.type === 'card') { console.log(`paid ${payment.amount} using ${payment.type} with number ${payment.cardNumber}`) } else { console.log(`paid ${payment.amount} using ${payment.type}`) } } logPayment({ type: 'cash', amount: 100 }) logPayment({ type: 'card', amount: 100, cardNumber: '0123456789' })
但如果把用来区分类型的type字段嵌套到metadata对象里,代码就会报错:
interface Cash { amount: number, // type 被嵌套在 metadata 属性内 metadata: { type: 'cash' } } interface Card { amount: number, cardNumber: string // type 被嵌套在 metadata 属性内 metadata: { type: 'card' } } type Payment = Cash | Card const logPayment = (payment: Payment) => { if (payment.metadata.type === 'card') { // 错误:Property 'cardNumber' does not exist on type 'Payment'. Property 'cardNumber' does not exist on type 'Cash'. console.log(`paid ${payment.amount} using ${payment.metadata.type} with number ${payment.cardNumber}`) } else { console.log(`paid ${payment.amount} using ${payment.metadata.type}`) } } logPayment({ metadata: { type: 'cash' }, amount: 100 }) logPayment({ metadata: { type: 'card' }, amount: 100, cardNumber: '0123456789' })
问题原因
TypeScript的类型收窄(控制流分析)只支持直接定义在联合类型成员顶层的字面量属性作为区分标识。
当你把区分类型的type放在嵌套的metadata对象里时,TypeScript没法建立起payment.metadata.type的取值和Payment联合类型中具体成员(Cash/Card)的关联,也就无法自动把payment的类型从Payment收窄到Card,自然会认为cardNumber可能不存在(因为Cash类型没有这个属性)。
简单说,TypeScript目前不支持用嵌套属性作为联合类型的区分符,必须把用来做类型判断的字面量字段放在接口的顶层。
内容的提问来源于stack exchange,提问作者Francesco Meli
相关产品推荐
相关产品推荐

