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

TypeScript特定类型处理函数传入联合类型入参函数报错修复

报错原因

复现代码如下:

interface DataOne {
    strings: string[],
}

interface DataTwo {
    numbers: number[],
}

const Component = (onDataReceived: (data: DataOne | DataTwo) => void) => {
    const data: DataOne | DataTwo = {numbers: [1, 2, 3]}
    onDataReceived(data)
}

const onDataOneReceived = (data: DataOne) => console.log(data)
Component(onDataOneReceived)

编译时报错:

Argument of type '(data: DataOne) => void' is not assignable to parameter of type '(data: DataOne | DataTwo) => void'. Types of parameters 'data' and 'data' are incompatible.
Type 'DataOne | DataTwo' is not assignable to type 'DataOne'.
Property 'strings' is missing in type 'DataTwo' but required in type 'DataOne'.

这个错误是TypeScript函数参数逆变校验的正常结果:Component声明的入参回调,必须能覆盖DataOne | DataTwo联合类型的所有取值场景,也就是回调要同时兼容两种数据类型。但你传入的onDataOneReceived只声明接收DataOne类型,一旦Component内部传入DataTwo类型数据,回调里访问strings属性就会出现运行时错误,因此TS直接拦截了这个不合法的类型传参。
之前尝试泛型、类型守卫没生效,基本是用法不对,下面两种方案都可以解决问题:

修复方案

方案1:回调内部做类型窄化(无需修改Component定义,适配所有场景)

把回调的参数类型声明为完整的联合类型,在回调内部通过类型守卫判断数据的实际类型,再执行对应逻辑,TS会自动完成类型窄化:

const onDataOneReceived = (data: DataOne | DataTwo) => {
  // 过滤非DataOne类型的场景
  if (!('strings' in data)) return
  // 此处TS会自动推导data为DataOne类型,可安全访问strings属性
  console.log(data.strings)
}
// 调用无类型报错
Component(onDataOneReceived)

如果需要同时处理两种数据类型,直接在判断分支里写对应逻辑即可:

const onDataReceived = (data: DataOne | DataTwo) => {
  if ('strings' in data) {
    console.log('字符串数组数据:', data.strings)
  } else {
    console.log('数字数组数据:', data.numbers)
  }
}
Component(onDataReceived)

方案2:为Component添加正确的泛型约束(适合Component返回数据类型可推导的场景)

如果Component的返回数据类型可以通过入参确定、不是内部随机生成的固定联合类型,可以用泛型关联入参回调和数据的类型,避免手动窄化:

// 约束泛型T为两个接口的联合类型
const Component = <T extends DataOne | DataTwo>(
  onDataReceived: (data: T) => void,
  sourceData: T
) => {
  onDataReceived(sourceData)
}

// 传入DataTwo类型数据时,TS自动推导回调参数为DataTwo,可直接访问numbers
Component((data) => {
  console.log(data.numbers)
}, { numbers: [1,2,3] })

// 传入DataOne类型数据时,TS自动推导回调参数为DataOne,可直接访问strings
Component((data) => {
  console.log(data.strings)
}, { strings: ['a', 'b'] })

注意:如果Component内部生成数据、类型不受外部入参控制,不要用泛型方案,必须在回调内部做类型窄化,否则会绕过TS的类型安全校验,埋下运行时错误隐患。

内容的提问来源于stack exchange,提问作者barciewicz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 19:24:26