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

嵌套接口中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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 04:20:33