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

如何让TypeScript中foobar(bar)因bar参数缺失b属性报错?

问题分析与解决

为什么当前代码不报错?

默认情况下,TypeScript的函数参数兼容性采用双向协变规则:只要两个函数的参数类型存在属性重叠(比如都包含a),就会被判定为兼容,哪怕其中一个参数缺少另一个的属性(比如bar的参数没有b)。若未开启strictFunctionTypes编译选项,TS不会对这种不严格的兼容进行报错。

即使开启strictFunctionTypes(启用参数逆变规则),bar的参数类型{a: string}与foo的参数类型{a: any, b: any}互相不属于子类型关系,此时TS会直接判定bar无法赋值给typeof foo,自然触发报错。

让foobar(bar)报错的两种方法

方法1:开启strictFunctionTypes编译选项

在tsconfig.json中添加或修改配置:

{
  "compilerOptions": {
    "strictFunctionTypes": true
  }
}

开启后,TS会严格遵循函数参数的逆变规则,bar因参数缺少b属性,会被直接标记为类型不兼容。

方法2:显式约束函数参数类型

如果不想依赖编译选项,可以通过类型工具显式约束foobar的入参必须能接受foo的完整参数类型:

const foo = (arg: {a: any, b: any}) => 1;

// 提取foo的参数类型
type RequiredParams = Parameters<typeof foo>[0];

// 强制要求传入的函数必须能处理RequiredParams类型的参数
const foobar = <T extends (arg: RequiredParams) => ReturnType<typeof foo>>(arg: T) => 1;

const bar = (arg: {a: string}) => 1;

foobar(bar); // 报错:类型不兼容

这种方式通过Parameters工具类型提取foo的参数结构,约束foobar的入参必须支持该结构,从而让缺少b的bar被判定为无效。

关于逆变的解释

函数参数的逆变规则是:若类型A是类型B的子类型,那么(B) => void是(A) => void的子类型。简单来说,能接受更宽泛参数(超类型)的函数,可以赋值给需要接受更具体参数(子类型)的函数类型。比如,能处理Animal的函数,必然能处理Dog(Dog是Animal的子类型),因此前者可以赋值给后者的类型。

在你的例子中,foo的参数是{a: any, b: any},bar的参数是{a: string},两者互相不属于子类型,所以在严格逆变模式下,bar无法兼容typeof foo,会触发报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 17:35:24